Merge "Fixed a heads up crash" into mnc-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 65214b8..37b1d7b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -141,6 +141,7 @@
     field public static final java.lang.String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
     field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
+    field public static final java.lang.String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
     field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
     field public static final java.lang.String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
     field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index dd3d3a8..9394d2c 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -321,6 +321,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that owns the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param account The account to query for a password. Must not be {@code null}.
      * @return The account's password, null if none or if the account doesn't exist
      */
@@ -345,6 +349,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that owns the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
+     * for this function in API level 22.
+     *
      * @param account The account to query for user data
      * @return The user data, null if the account or key doesn't exist
      */
@@ -493,6 +501,10 @@
      * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
      * authenticator that owns the account type.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
+     * or signature match. See docs for this function in API level 22.
+     *
      * @param type The type of accounts to return, null to retrieve all accounts
      * @return An array of {@link Account}, one per matching account.  Empty
      *     (never null) if no accounts of the specified type have been added.
@@ -623,6 +635,11 @@
      * @param type The type of accounts to return, must not be null
      * @param features An array of the account features to require,
      *     may be null or empty
+     *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
+     * or signature match. See docs for this function in API level 22.
+     *
      * @param callback Callback to invoke when the request completes,
      *     null for no callback
      * @param handler {@link Handler} identifying the callback thread,
@@ -668,6 +685,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that owns the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
+     * for this function in API level 22.
+     *
      * @param account The {@link Account} to add
      * @param password The password to associate with the account, null for none
      * @param userdata String values to use for the account's userdata, null for
@@ -720,6 +741,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
+     * is needed for those platforms. See docs for this function in API level 22.
+     *
      * @param account The {@link Account} to rename
      * @param newName String name to be associated with the account.
      * @param callback Callback to invoke when the request completes, null for
@@ -784,6 +809,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param account The {@link Account} to remove
      * @param callback Callback to invoke when the request completes,
      *     null for no callback
@@ -826,6 +855,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param account The {@link Account} to remove
      * @param activity The {@link Activity} context to use for launching a new
      *     authenticator-defined sub-Activity to prompt the user to delete an
@@ -919,6 +952,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
+     * is needed for those platforms. See docs for this function in API level 22.
+     *
      * @param account The {@link Account} to delete.
      * @return True if the account was successfully deleted, false if the
      *         account did not exist, the account is null, or another error
@@ -943,6 +980,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS or USE_CREDENTIALS permission is needed for those
+     * platforms. See docs for this function in API level 22.
+     *
      * @param accountType The account type of the auth token to invalidate, must not be null
      * @param authToken The auth token to invalidate, may be null
      */
@@ -969,6 +1010,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
+     * is needed for those platforms. See docs for this function in API level 22.
+     *
      * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
      * @param authTokenType The type of auth token to fetch. Cannot be {@code null}. 
      * @return The cached auth token for this account and type, or null if
@@ -998,6 +1043,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
+     * is needed for those platforms. See docs for this function in API level 22.
+     *
      * @param account The account whose password is to be set. Cannot be
      *            {@code null}.
      * @param password The password to set, null to clear the password
@@ -1025,6 +1074,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param account The account whose password to clear
      */
     public void clearPassword(final Account account) {
@@ -1047,6 +1100,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
+     * is needed for those platforms. See docs for this function in API level 22.
+     *
      * @param account Account whose user data is to be set. Must not be {@code null}.
      * @param key String user data key to set.  Must not be null
      * @param value String value to set, {@code null} to clear this user data key
@@ -1073,6 +1130,10 @@
      * <p>This method requires the caller to have a signature match with the
      * authenticator that manages the specified account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
+     * is needed for those platforms. See docs for this function in API level 22.
+     *
      * @param account The account to set an auth token for
      * @param authTokenType The type of the auth token, see {#getAuthToken}
      * @param authToken The auth token to add to the cache
@@ -1095,6 +1156,10 @@
      * <p>This method may block while a network request completes, and must
      * never be made from the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * USE_CREDENTIALS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param account The account to fetch an auth token for
      * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
      * @param notifyAuthFailure If true, display a notification and return null
@@ -1143,6 +1208,10 @@
      * access different functionality -- for example, Google uses different auth
      * tokens to access Gmail and Google Calendar for the same account.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * USE_CREDENTIALS permission is needed for those platforms. See docs for 
+     * this function in API level 22.
+     *
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
@@ -1306,6 +1375,10 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * USE_CREDENTIALS permission is needed for those platforms. See docs for 
+     * this function in API level 22.
+     *
      * @param account The account to fetch an auth token for
      * @param authTokenType The auth token type, an authenticator-dependent
      *     string token, must not be null
@@ -1369,6 +1442,10 @@
      *
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
+     * 
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
      *
      * @param accountType The type of account to add; must not be null
      * @param authTokenType The type of auth token (see {@link #getAuthToken})
@@ -1551,6 +1628,10 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
+     * for this function in API level 22.
+     *
      * @param account The account to confirm password knowledge for
      * @param options Authenticator-specific options for the request;
      *     if the {@link #KEY_PASSWORD} string field is present, the
@@ -1629,6 +1710,10 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param account The account to update credentials for
      * @param authTokenType The credentials entered must allow an auth token
      *     of this type to be created (but no actual auth token is returned);
@@ -1689,6 +1774,10 @@
      * <p>This method requires the caller to have the same signature as the
      * authenticator associated with the specified account type.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
+     * for this function in API level 22.
+     *
      * @param accountType The account type associated with the authenticator
      *     to adjust
      * @param activity The {@link Activity} context to use for launching a new
@@ -2209,6 +2298,10 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
+     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
+     * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
+     * this function in API level 22.
+     *
      * @param accountType The account type required
      *     (see {@link #getAccountsByType}), must not be null
      * @param authTokenType The desired auth token type
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fc71783..f3f2428 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -930,9 +930,9 @@
         private Action(Parcel in) {
             if (in.readInt() != 0) {
                 mIcon = Icon.CREATOR.createFromParcel(in);
-            }
-            if (mIcon.getType() == Icon.TYPE_RESOURCE) {
-                icon = mIcon.getResId();
+                if (mIcon.getType() == Icon.TYPE_RESOURCE) {
+                    icon = mIcon.getResId();
+                }
             }
             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             if (in.readInt() == 1) {
@@ -3174,7 +3174,8 @@
             RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(),
                     tombstone ? getActionTombstoneLayoutResource()
                               : getActionLayoutResource());
-            button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0);
+            final Icon ai = action.getIcon();
+            button.setTextViewCompoundDrawablesRelative(R.id.action0, ai, null, null, null);
             button.setTextViewText(R.id.action0, processLegacyText(action.title));
             if (!tombstone) {
                 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
@@ -3193,7 +3194,7 @@
         }
 
         private void processLegacyAction(Action action, RemoteViews button) {
-            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.icon)) {
+            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.getIcon())) {
                 button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
                         mContext.getColor(R.color.notification_action_color_filter),
                         PorterDuff.Mode.MULTIPLY);
@@ -3608,7 +3609,6 @@
             mContentText = extras.getCharSequence(EXTRA_TEXT);
             mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
             mContentInfo = extras.getCharSequence(EXTRA_INFO_TEXT);
-            mSmallIcon = extras.getParcelable(EXTRA_SMALL_ICON);
             mProgress = extras.getInt(EXTRA_PROGRESS);
             mProgressMax = extras.getInt(EXTRA_PROGRESS_MAX);
             mProgressIndeterminate = extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
@@ -4442,7 +4442,7 @@
             final boolean tombstone = (action.actionIntent == null);
             RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(),
                     R.layout.notification_material_media_action);
-            button.setImageViewResource(R.id.action0, action.icon);
+            button.setImageViewIcon(R.id.action0, action.getIcon());
             button.setDrawableParameters(R.id.action0, false, -1,
                     0xFFFFFFFF,
                     PorterDuff.Mode.SRC_ATOP, -1);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 514d24a..651fb35 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -626,6 +626,7 @@
                 case NET_CAPABILITY_TRUSTED:        capabilities += "TRUSTED"; break;
                 case NET_CAPABILITY_NOT_VPN:        capabilities += "NOT_VPN"; break;
                 case NET_CAPABILITY_VALIDATED:      capabilities += "VALIDATED"; break;
+                case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break;
             }
             if (++i < types.length) capabilities += "&";
         }
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 243ddf7..521df28 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -292,7 +292,9 @@
 
                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                 //noinspection unchecked
-                return postResult(doInBackground(mParams));
+                Result result = doInBackground(mParams);
+                Binder.flushPendingCommands();
+                return postResult(result);
             }
         };
 
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 0eda692..2cab914 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -17,6 +17,9 @@
 package android.service.notification;
 
 import android.app.Notification;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
@@ -40,6 +43,7 @@
     private final long postTime;
 
     private final int score;
+    private Context mContext; // used for inflation & icon expansion
 
     /** @hide */
     public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
@@ -261,4 +265,24 @@
     public String getGroupKey() {
         return groupKey;
     }
+
+    /**
+     * @hide
+     */
+    public Context getPackageContext(Context context) {
+        if (mContext == null) {
+            try {
+                ApplicationInfo ai = context.getPackageManager()
+                        .getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
+                mContext = context.createApplicationContext(ai,
+                        Context.CONTEXT_RESTRICTED);
+            } catch (PackageManager.NameNotFoundException e) {
+                mContext = null;
+            }
+        }
+        if (mContext == null) {
+            mContext = context;
+        }
+        return mContext;
+    }
 }
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 0b5824a..dcb2437 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -25,7 +25,6 @@
 import android.text.format.Time;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.widget.TextView;
 import android.widget.RemoteViews.RemoteView;
 
 import java.text.DateFormat;
@@ -228,14 +227,14 @@
             final boolean register = mAttachedViews.isEmpty();
             mAttachedViews.add(v);
             if (register) {
-                register(v.getContext().getApplicationContext());
+                register(getApplicationContextIfAvailable(v.getContext()));
             }
         }
 
         public void removeView(DateTimeView v) {
             mAttachedViews.remove(v);
             if (mAttachedViews.isEmpty()) {
-                unregister(v.getContext().getApplicationContext());
+                unregister(getApplicationContextIfAvailable(v.getContext()));
             }
         }
 
@@ -258,6 +257,11 @@
             return result;
         }
 
+        static final Context getApplicationContextIfAvailable(Context context) {
+            final Context ac = context.getApplicationContext();
+            return ac != null ? ac : context;
+        }
+
         void register(Context context) {
             final IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_TIME_TICK);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 4b40501..47e894a 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -722,8 +722,10 @@
             LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
 
             totalWeight += lp.weight;
-            
-            if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
+
+            final boolean fillExcessSpace = lp.weight > 0;
+            final boolean hasZeroHeight = lp.height == 0;
+            if (heightMode == MeasureSpec.EXACTLY && fillExcessSpace && hasZeroHeight) {
                 // Optimization: don't bother measuring children who are going to use
                 // leftover space. These views will get measured again down below if
                 // there is any leftover space.
@@ -731,12 +733,12 @@
                 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
                 skippedMeasure = true;
             } else {
-                final boolean fillExcessSpace = lp.height == 0 && lp.weight > 0;
-                if (fillExcessSpace) {
-                    // heightMode is either UNSPECIFIED or AT_MOST, and this
-                    // child wanted to stretch to fill available space.
-                    // Translate that to WRAP_CONTENT so that it does not end up
-                    // with a height of 0.
+                if (fillExcessSpace && hasZeroHeight) {
+                    // The LinearLayout's heightMode is either UNSPECIFIED or
+                    // AT_MOST, and this child wanted to stretch to fill
+                    // available space. Translate the explicit height of 0 to
+                    // WRAP_CONTENT so that we can measure the view's ideal
+                    // height.
                     lp.height = LayoutParams.WRAP_CONTENT;
                 }
 
@@ -751,7 +753,11 @@
                 final int childHeight = child.getMeasuredHeight();
                 if (fillExcessSpace) {
                     usedExcessSpace += childHeight;
-                    lp.height = 0;
+
+                    // Restore original layout height.
+                    if (hasZeroHeight) {
+                        lp.height = 0;
+                    }
                 }
 
                 final int totalLength = mTotalLength;
@@ -1047,8 +1053,10 @@
                     child.getLayoutParams();
 
             totalWeight += lp.weight;
-            
-            if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
+
+            final boolean fillExcessSpace = lp.weight > 0;
+            final boolean hasZeroWidth = lp.width == 0;
+            if (widthMode == MeasureSpec.EXACTLY && fillExcessSpace && hasZeroWidth) {
                 // Optimization: don't bother measuring children who are going to use
                 // leftover space. These views will get measured again down below if
                 // there is any leftover space.
@@ -1075,12 +1083,12 @@
                     skippedMeasure = true;
                 }
             } else {
-                final boolean fillExcessSpace = lp.width == 0 && lp.weight > 0;
-                if (fillExcessSpace) {
-                    // widthMode is either UNSPECIFIED or AT_MOST, and this
-                    // child wanted to stretch to fill available space.
-                    // Translate that to WRAP_CONTENT so that it does not end up
-                    // with a width of 0.
+                if (fillExcessSpace && hasZeroWidth) {
+                    // The LinearLayout's widthMode is either UNSPECIFIED or
+                    // AT_MOST, and this child wanted to stretch to fill
+                    // available space. Translate the explicit height of 0 to
+                    // WRAP_CONTENT so that we can measure the view's ideal
+                    // width.
                     lp.width = LayoutParams.WRAP_CONTENT;
                 }
 
@@ -1095,7 +1103,11 @@
                 final int childWidth = child.getMeasuredWidth();
                 if (fillExcessSpace) {
                     usedExcessSpace += childWidth;
-                    lp.width = 0;
+
+                    // Restore the original layout width.
+                    if (hasZeroWidth) {
+                        lp.width = 0;
+                    }
                 }
 
                 if (isExactly) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 74843ee..d158313 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1412,39 +1412,108 @@
         public TextViewDrawableAction(int viewId, boolean isRelative, int d1, int d2, int d3, int d4) {
             this.viewId = viewId;
             this.isRelative = isRelative;
+            this.useIcons = false;
             this.d1 = d1;
             this.d2 = d2;
             this.d3 = d3;
             this.d4 = d4;
         }
 
+        public TextViewDrawableAction(int viewId, boolean isRelative,
+                Icon i1, Icon i2, Icon i3, Icon i4) {
+            this.viewId = viewId;
+            this.isRelative = isRelative;
+            this.useIcons = true;
+            this.i1 = i1;
+            this.i2 = i2;
+            this.i3 = i3;
+            this.i4 = i4;
+        }
+
         public TextViewDrawableAction(Parcel parcel) {
             viewId = parcel.readInt();
             isRelative = (parcel.readInt() != 0);
-            d1 = parcel.readInt();
-            d2 = parcel.readInt();
-            d3 = parcel.readInt();
-            d4 = parcel.readInt();
+            useIcons = (parcel.readInt() != 0);
+            if (useIcons) {
+                if (parcel.readInt() != 0) {
+                    i1 = Icon.CREATOR.createFromParcel(parcel);
+                }
+                if (parcel.readInt() != 0) {
+                    i2 = Icon.CREATOR.createFromParcel(parcel);
+                }
+                if (parcel.readInt() != 0) {
+                    i3 = Icon.CREATOR.createFromParcel(parcel);
+                }
+                if (parcel.readInt() != 0) {
+                    i4 = Icon.CREATOR.createFromParcel(parcel);
+                }
+            } else {
+                d1 = parcel.readInt();
+                d2 = parcel.readInt();
+                d3 = parcel.readInt();
+                d4 = parcel.readInt();
+            }
         }
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(TAG);
             dest.writeInt(viewId);
             dest.writeInt(isRelative ? 1 : 0);
-            dest.writeInt(d1);
-            dest.writeInt(d2);
-            dest.writeInt(d3);
-            dest.writeInt(d4);
+            dest.writeInt(useIcons ? 1 : 0);
+            if (useIcons) {
+                if (i1 != null) {
+                    dest.writeInt(1);
+                    i1.writeToParcel(dest, 0);
+                } else {
+                    dest.writeInt(0);
+                }
+                if (i2 != null) {
+                    dest.writeInt(1);
+                    i2.writeToParcel(dest, 0);
+                } else {
+                    dest.writeInt(0);
+                }
+                if (i3 != null) {
+                    dest.writeInt(1);
+                    i3.writeToParcel(dest, 0);
+                } else {
+                    dest.writeInt(0);
+                }
+                if (i4 != null) {
+                    dest.writeInt(1);
+                    i4.writeToParcel(dest, 0);
+                } else {
+                    dest.writeInt(0);
+                }
+            } else {
+                dest.writeInt(d1);
+                dest.writeInt(d2);
+                dest.writeInt(d3);
+                dest.writeInt(d4);
+            }
         }
 
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
             final TextView target = (TextView) root.findViewById(viewId);
             if (target == null) return;
-            if (isRelative) {
-                target.setCompoundDrawablesRelativeWithIntrinsicBounds(d1, d2, d3, d4);
+            if (useIcons) {
+                final Context ctx = target.getContext();
+                final Drawable id1 = i1 == null ? null : i1.loadDrawable(ctx);
+                final Drawable id2 = i2 == null ? null : i2.loadDrawable(ctx);
+                final Drawable id3 = i3 == null ? null : i3.loadDrawable(ctx);
+                final Drawable id4 = i4 == null ? null : i4.loadDrawable(ctx);
+                if (isRelative) {
+                    target.setCompoundDrawablesRelativeWithIntrinsicBounds(id1, id2, id3, id4);
+                } else {
+                    target.setCompoundDrawablesWithIntrinsicBounds(id1, id2, id3, id4);
+                }
             } else {
-                target.setCompoundDrawablesWithIntrinsicBounds(d1, d2, d3, d4);
+                if (isRelative) {
+                    target.setCompoundDrawablesRelativeWithIntrinsicBounds(d1, d2, d3, d4);
+                } else {
+                    target.setCompoundDrawablesWithIntrinsicBounds(d1, d2, d3, d4);
+                }
             }
         }
 
@@ -1453,7 +1522,9 @@
         }
 
         boolean isRelative = false;
+        boolean useIcons = false;
         int d1, d2, d3, d4;
+        Icon i1, i2, i3, i4;
 
         public final static int TAG = 11;
     }
@@ -2067,6 +2138,41 @@
     }
 
     /**
+     * Equivalent to calling {@link
+     * TextView#setCompoundDrawablesWithIntrinsicBounds(Drawable, Drawable, Drawable, Drawable)}
+     * using the drawables yielded by {@link Icon#loadDrawable(Context)}.
+     *
+     * @param viewId The id of the view whose text should change
+     * @param left an Icon to place to the left of the text, or 0
+     * @param top an Icon to place above the text, or 0
+     * @param right an Icon to place to the right of the text, or 0
+     * @param bottom an Icon to place below the text, or 0
+     *
+     * @hide
+     */
+    public void setTextViewCompoundDrawables(int viewId, Icon left, Icon top, Icon right, Icon bottom) {
+        addAction(new TextViewDrawableAction(viewId, false, left, top, right, bottom));
+    }
+
+    /**
+     * Equivalent to calling {@link
+     * TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable, Drawable, Drawable, Drawable)}
+     * using the drawables yielded by {@link Icon#loadDrawable(Context)}.
+     *
+     * @param viewId The id of the view whose text should change
+     * @param start an Icon to place before the text (relative to the
+     * layout direction), or 0
+     * @param top an Icon to place above the text, or 0
+     * @param end an Icon to place after the text, or 0
+     * @param bottom an Icon to place below the text, or 0
+     *
+     * @hide
+     */
+    public void setTextViewCompoundDrawablesRelative(int viewId, Icon start, Icon top, Icon end, Icon bottom) {
+        addAction(new TextViewDrawableAction(viewId, true, start, top, end, bottom));
+    }
+
+    /**
      * Equivalent to calling ImageView.setImageResource
      *
      * @param viewId The id of the view whose drawable should change
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 131ba46..a1462c4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2270,6 +2270,7 @@
      * @attr ref android.R.styleable#TextView_drawableRight
      * @attr ref android.R.styleable#TextView_drawableBottom
      */
+    @android.view.RemotableViewMethod
     public void setCompoundDrawablesWithIntrinsicBounds(@Nullable Drawable left,
             @Nullable Drawable top, @Nullable Drawable right, @Nullable Drawable bottom) {
 
@@ -2302,6 +2303,7 @@
      * @attr ref android.R.styleable#TextView_drawableEnd
      * @attr ref android.R.styleable#TextView_drawableBottom
      */
+    @android.view.RemotableViewMethod
     public void setCompoundDrawablesRelative(@Nullable Drawable start, @Nullable Drawable top,
             @Nullable Drawable end, @Nullable Drawable bottom) {
         Drawables dr = mDrawables;
@@ -2472,6 +2474,7 @@
      * @attr ref android.R.styleable#TextView_drawableEnd
      * @attr ref android.R.styleable#TextView_drawableBottom
      */
+    @android.view.RemotableViewMethod
     public void setCompoundDrawablesRelativeWithIntrinsicBounds(@Nullable Drawable start,
             @Nullable Drawable top, @Nullable Drawable end, @Nullable Drawable bottom) {
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1f49929..1f47ce3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -961,9 +961,7 @@
         android:label="@string/permlab_changeWimaxState"
         android:protectionLevel="normal" />
 
-    <!--@SystemApi Allows applications to the the local WiFi and Bluetooth MAC address.
-        @hide
-    -->
+    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
     <permission android:name="android.permission.SCORE_NETWORKS"
         android:protectionLevel="signature|privileged" />
 
@@ -2583,10 +2581,16 @@
     <permission android:name="android.permission.KILL_UID"
                 android:protectionLevel="signature|installer" />
 
-    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+    <!-- @SystemApi Allows applications to read the local WiFi and Bluetooth MAC address.
+        @hide -->
     <permission android:name="android.permission.LOCAL_MAC_ADDRESS"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
+        @hide -->
+    <permission android:name="android.permission.PEERS_MAC_ADDRESS"
+                android:protectionLevel="signature" />
+
     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
         can use this permission to ensure incoming Nfc messages are from the Nfc stack
         and not simulated by another application.
diff --git a/core/res/res/values-land/dimens_material.xml b/core/res/res/values-land/dimens_material.xml
index 202f4a4..660210a 100644
--- a/core/res/res/values-land/dimens_material.xml
+++ b/core/res/res/values-land/dimens_material.xml
@@ -17,8 +17,6 @@
 
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height_material">48dp</dimen>
-    <!-- Default padding of an action bar. -->
-    <dimen name="action_bar_default_padding_material">0dp</dimen>
     <!-- Default text size for action bar title.-->
     <dimen name="text_size_title_material_toolbar">14dp</dimen>
     <!-- Default text size for action bar subtitle.-->
diff --git a/core/res/res/values-sw600dp/dimens_material.xml b/core/res/res/values-sw600dp/dimens_material.xml
index dffe8e7..3bbb352 100644
--- a/core/res/res/values-sw600dp/dimens_material.xml
+++ b/core/res/res/values-sw600dp/dimens_material.xml
@@ -21,13 +21,11 @@
     <dimen name="text_size_subtitle_material_toolbar">16dp</dimen>
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height_material">64dp</dimen>
-    <!-- Default padding of an action bar. -->
-    <dimen name="action_bar_default_padding_material">4dp</dimen>
     <!-- Default content inset of an action bar. -->
     <dimen name="action_bar_content_inset_material">24dp</dimen>
 
-    <!-- Padding to add to the start of the overflow action button. -->
-    <dimen name="action_bar_navigation_padding_start_material">8dp</dimen>
-    <!-- Padding to add to the end of the overflow action button. -->
-    <dimen name="action_bar_overflow_padding_end_material">18dp</dimen>
+    <!-- Default start padding of an action bar. -->
+    <dimen name="action_bar_default_padding_start_material">8dp</dimen>
+    <!-- Default end padding of an action bar. -->
+    <dimen name="action_bar_default_padding_end_material">8dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 558afa7..55bea9e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -35,8 +35,10 @@
 
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height_material">56dp</dimen>
-    <!-- Default padding of an action bar. -->
-    <dimen name="action_bar_default_padding_material">4dp</dimen>
+    <!-- Default start padding of an action bar. -->
+    <dimen name="action_bar_default_padding_start_material">0dp</dimen>
+    <!-- Default end padding of an action bar. -->
+    <dimen name="action_bar_default_padding_end_material">0dp</dimen>
     <!-- Default content inset of an action bar. -->
     <dimen name="action_bar_content_inset_material">16dp</dimen>
     <!-- Vertical padding around action bar icons. -->
@@ -51,8 +53,6 @@
     <dimen name="list_item_padding_horizontal_material">@dimen/action_bar_content_inset_material</dimen>
 
     <!-- Padding to add to the start of the overflow action button. -->
-    <dimen name="action_bar_navigation_padding_start_material">0dp</dimen>
-    <!-- Padding to add to the start of the overflow action button. -->
     <dimen name="action_bar_overflow_padding_start_material">6dp</dimen>
     <!-- Padding to add to the end of the overflow action button. -->
     <dimen name="action_bar_overflow_padding_end_material">10dp</dimen>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 1b9c409..1e202e4 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -809,13 +809,14 @@
         <item name="navigationButtonStyle">@style/Widget.Material.Toolbar.Button.Navigation</item>
         <item name="titleTextAppearance">@style/TextAppearance.Material.Widget.Toolbar.Title</item>
         <item name="subtitleTextAppearance">@style/TextAppearance.Material.Widget.Toolbar.Subtitle</item>
+        <item name="paddingStart">@dimen/action_bar_default_padding_start_material</item>
+        <item name="paddingEnd">@dimen/action_bar_default_padding_end_material</item>
     </style>
 
     <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Material">
         <item name="background">@drawable/control_background_40dp_material</item>
         <item name="minWidth">56dp</item>
         <item name="scaleType">center</item>
-        <item name="paddingStart">@dimen/action_bar_navigation_padding_start_material</item>
     </style>
 
     <style name="Widget.Material.WebTextView" parent="Widget.WebTextView"/>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 94ed8b4..56cc44c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -18,16 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.IBinder;
 import android.security.KeyStore;
-import android.security.KeyStoreException;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -103,91 +98,6 @@
         protected final int getAdditionalEntropyAmountForFinish() {
             return 0;
         }
-
-        @Override
-        @NonNull
-        protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
-                KeyStore keyStore, IBinder operationToken) {
-            if (isEncrypting()) {
-                // KeyStore's RSA encryption without padding expects the input to be of the same
-                // length as the modulus. We thus have to buffer all input to pad it with leading
-                // zeros.
-                return new ZeroPaddingEncryptionStreamer(
-                        super.createMainDataStreamer(keyStore, operationToken),
-                        getModulusSizeBytes());
-            } else {
-                return super.createMainDataStreamer(keyStore, operationToken);
-            }
-        }
-
-        /**
-         * Streamer which buffers all plaintext input, then pads it with leading zeros to match
-         * modulus size, and then sends it into KeyStore to obtain ciphertext.
-         */
-        private static class ZeroPaddingEncryptionStreamer
-                implements KeyStoreCryptoOperationStreamer {
-
-            private final KeyStoreCryptoOperationStreamer mDelegate;
-            private final int mModulusSizeBytes;
-            private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
-            private long mConsumedInputSizeBytes;
-
-            private ZeroPaddingEncryptionStreamer(
-                    KeyStoreCryptoOperationStreamer delegate,
-                    int modulusSizeBytes) {
-                mDelegate = delegate;
-                mModulusSizeBytes = modulusSizeBytes;
-            }
-
-            @Override
-            public byte[] update(byte[] input, int inputOffset, int inputLength)
-                    throws KeyStoreException {
-                if (inputLength > 0) {
-                    mInputBuffer.write(input, inputOffset, inputLength);
-                    mConsumedInputSizeBytes += inputLength;
-                }
-                return EmptyArray.BYTE;
-            }
-
-            @Override
-            public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
-                    byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
-                if (inputLength > 0) {
-                    mConsumedInputSizeBytes += inputLength;
-                    mInputBuffer.write(input, inputOffset, inputLength);
-                }
-                byte[] bufferedInput = mInputBuffer.toByteArray();
-                mInputBuffer.reset();
-                byte[] paddedInput;
-                if (bufferedInput.length < mModulusSizeBytes) {
-                    // Pad input with leading zeros
-                    paddedInput = new byte[mModulusSizeBytes];
-                    System.arraycopy(
-                            bufferedInput, 0,
-                            paddedInput,
-                            paddedInput.length - bufferedInput.length,
-                            bufferedInput.length);
-                } else {
-                    // RI throws BadPaddingException in this scenario. INVALID_ARGUMENT below will
-                    // be translated into BadPaddingException.
-                    throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT,
-                            "Message size (" + bufferedInput.length + " bytes) must be smaller than"
-                            + " modulus (" + mModulusSizeBytes + " bytes)");
-                }
-                return mDelegate.doFinal(paddedInput, 0, paddedInput.length, signature,
-                        additionalEntropy);
-            }
-
-            @Override
-            public long getConsumedInputSizeBytes() {
-                return mConsumedInputSizeBytes;
-            }
-
-            @Override
-            public long getProducedOutputSizeBytes() {
-                return mDelegate.getProducedOutputSizeBytes();
-            }
-        }
     }
 
     /**
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index 92a057d..319cfe4 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -60,8 +60,14 @@
 }
 
 void Stencil::clear() {
+    glStencilMask(0xff);
     glClearStencil(0);
     glClear(GL_STENCIL_BUFFER_BIT);
+
+    if (mState == kTest) {
+        // reset to test state, with immutable stencil
+        glStencilMask(0);
+    }
 }
 
 void Stencil::enableTest(int incrementThreshold) {
@@ -104,17 +110,17 @@
     // We only want to test, let's keep everything
     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
     mState = kTest;
+    glStencilMask(0);
 }
 
 void Stencil::enableDebugWrite() {
-    if (mState != kWrite) {
-        enable();
-        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
-        // The test always passes so the first two values are meaningless
-        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-        mState = kWrite;
-    }
+    enable();
+    glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
+    // The test always passes so the first two values are meaningless
+    glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+    mState = kWrite;
+    glStencilMask(0xff);
 }
 
 void Stencil::enable() {
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index 93fb6d2..e1990cd 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -113,8 +113,13 @@
     /**
      * Called to open a {@link MidiInputPort} for the specified port number.
      *
+     * An input port can only be used by one sender at a time.
+     * Opening an input port will fail if another application has already opened it for use.
+     * A {@link MidiDeviceStatus} can be used to determine if an input port is already open.
+     *
      * @param portNumber the number of the input port to open
-     * @return the {@link MidiInputPort}
+     * @return the {@link MidiInputPort} if the open is successful,
+     *         or null in case of failure.
      */
     public MidiInputPort openInputPort(int portNumber) {
         try {
@@ -133,8 +138,11 @@
     /**
      * Called to open a {@link MidiOutputPort} for the specified port number.
      *
+     * An output port may be opened by multiple applications.
+     *
      * @param portNumber the number of the output port to open
-     * @return the {@link MidiOutputPort}
+     * @return the {@link MidiOutputPort} if the open is successful,
+     *         or null in case of failure.
      */
     public MidiOutputPort openOutputPort(int portNumber) {
         try {
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 673c4ba..7baa5bc 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -31,7 +31,7 @@
   <li> Timestamps to avoid jitter.</li>
   <li> Support creation of <em>virtual MIDI devices</em> that can be connected to other devices.
   An example might be a synthesizer app that can be controlled by a composing app.</li>
-  <li> Support direction connection or &ldquo;patching&rdquo; of devices for lower latency.</li>
+  <li> Support direct connection or &ldquo;patching&rdquo; of devices for lower latency.</li>
 </ul>
 
 <h2 id=transports_supported>Transports Supported</h2>
@@ -75,6 +75,18 @@
 &lt;uses-feature android:name="android.software.midi" android:required="true"/>
 </pre>
 
+<h2 id=check_feature>Check for Feature Support</h2>
+
+<p>An app can also check at run-time whether the MIDI feature is supported on a platform.
+This is particularly useful during development when you install apps directly on a device.
+</p>
+
+<pre class=prettyprint>
+if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+    // do MIDI stuff
+}
+</pre>
+
 <h2 id=the_midimanager>The MidiManager</h2>
 
 
@@ -338,5 +350,54 @@
     }
 }
 </pre>
+
+<h1 id=using_midi_btle>Using MIDI Over Bluetooth LE</h1>
+
+<p>MIDI devices can be connected to Android using Bluetooth LE.</p>
+
+<p>Before using the device, the app must scan for available BTLE devices and then allow
+the user to connect. An example program
+will be provided so look for it on the Android developer website.</p>
+
+<h2 id=btle_location_permissions>Request Location Permission for BTLE</h2>
+
+<p>Applications that scan for Bluetooth devices must request permission in the
+manifest file. This LOCATION permission is required because it may be possible to
+guess the location of an Android device by seeing which BTLE devices are nearby.</p>
+
+<pre class=prettyprint>
+&lt;uses-permission android:name="android.permission.BLUETOOTH"/>
+&lt;uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+&lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+</pre>
+
+<p>Apps must also request location permission from the user at run-time.
+See the documentation for <code>Activity.requestPermissions()</code> for details and an example.
+</p>
+
+<h2 id=btle_scan_devices>Scan for MIDI Devices</h2>
+
+<p>The app will only want to see MIDI devices and not mice or other non-MIDI devices.
+So construct a ScanFilter using the UUID for standard MIDI over BTLE.</p>
+
+<pre class=prettyprint>
+MIDI over BTLE UUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700"
+</pre>
+
+<h2 id=btle_open_device>Open a MIDI Bluetooth Device</h2>
+
+<p>See the documentation for <code>android.bluetooth.le.BluetoothLeScanner.startScan()</code>
+method for details. When the user selects a MIDI/BTLE device then you can open it
+using the MidiManager.</p>
+
+<pre class=prettyprint>
+m.openBluetoothDevice(bluetoothDevice, callback, handler);
+</pre>
+
+<p>Once the MIDI/BTLE device has been opened by one app then it will also become available to other
+apps using the
+<a href="#get_list_of_already_plugged_in_entities">MIDI device discovery calls described above</a>.
+</p>
+
 </body>
 </html>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9df0818..c7adc98 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -380,9 +380,7 @@
 
     private void handleFingerprintAuthFailed() {
         releaseFingerprintWakeLock();
-        stopListeningForFingerprint();
         handleFingerprintHelp(-1, mContext.getString(R.string.fingerprint_not_recognized));
-        updateFingerprintListeningState();
     }
 
     private void handleFingerprintAcquired(int acquireInfo) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index ea2cc51..bbef259 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -60,7 +60,7 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
-
+    <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
     <!-- Physical hardware -->
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 41b37b0..9c37263 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1328,14 +1328,20 @@
         View bigContentViewLocal = null;
         View headsUpContentViewLocal = null;
         try {
-            contentViewLocal = contentView.apply(mContext, contentContainer,
+            contentViewLocal = contentView.apply(
+                    sbn.getPackageContext(mContext),
+                    contentContainer,
                     mOnClickHandler);
             if (bigContentView != null) {
-                bigContentViewLocal = bigContentView.apply(mContext, contentContainer,
+                bigContentViewLocal = bigContentView.apply(
+                        sbn.getPackageContext(mContext),
+                        contentContainer,
                         mOnClickHandler);
             }
             if (headsUpContentView != null) {
-                headsUpContentViewLocal = headsUpContentView.apply(mContext, contentContainer,
+                headsUpContentViewLocal = headsUpContentView.apply(
+                        sbn.getPackageContext(mContext),
+                        contentContainer,
                         mOnClickHandler);
             }
         }
@@ -1362,7 +1368,8 @@
         View publicViewLocal = null;
         if (publicNotification != null) {
             try {
-                publicViewLocal = publicNotification.contentView.apply(mContext,
+                publicViewLocal = publicNotification.contentView.apply(
+                        sbn.getPackageContext(mContext),
                         contentContainerPublic, mOnClickHandler);
 
                 if (publicViewLocal != null) {
@@ -1981,15 +1988,18 @@
         // Reapply the RemoteViews
         contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
         if (bigContentView != null && entry.getExpandedContentView() != null) {
-            bigContentView.reapply(mContext, entry.getExpandedContentView(),
+            bigContentView.reapply(notification.getPackageContext(mContext),
+                    entry.getExpandedContentView(),
                     mOnClickHandler);
         }
         View headsUpChild = entry.getHeadsUpContentView();
         if (headsUpContentView != null && headsUpChild != null) {
-            headsUpContentView.reapply(mContext, headsUpChild, mOnClickHandler);
+            headsUpContentView.reapply(notification.getPackageContext(mContext),
+                    headsUpChild, mOnClickHandler);
         }
         if (publicContentView != null && entry.getPublicContentView() != null) {
-            publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
+            publicContentView.reapply(notification.getPackageContext(mContext),
+                    entry.getPublicContentView(), mOnClickHandler);
         }
         // update the contentIntent
         mNotificationClicker.register(entry.row, notification);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index a0aa569..83b953e 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -8091,6 +8091,7 @@
             keyValueAgentCleanup();
         }
 
+        // TODO: clean up naming; this is now used at finish by both k/v and stream restores
         void keyValueAgentCleanup() {
             mBackupDataName.delete();
             mStageName.delete();
@@ -8126,8 +8127,17 @@
                     // usual full initialization.  Note that this is only done for
                     // full-system restores: when a single app has requested a restore,
                     // it is explicitly not killed following that operation.
-                    if (mTargetPackage == null && (mCurrentPackage.applicationInfo.flags
-                            & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
+                    //
+                    // We execute this kill when these conditions hold:
+                    //    1. the app did not request its own restore (mTargetPackage == null), and either
+                    //    2a. the app is a full-data target (TYPE_FULL_STREAM) or
+                    //     b. the app does not state android:killAfterRestore="false" in its manifest
+                    final int appFlags = mCurrentPackage.applicationInfo.flags;
+                    final boolean killAfterRestore =
+                            (mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
+                            || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0);
+
+                    if (mTargetPackage == null && killAfterRestore) {
                         if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
                                 + mCurrentPackage.applicationInfo.processName);
                         mActivityManager.killApplicationProcess(
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0b610ae..da94532 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2142,6 +2142,10 @@
                 mDefaultInetConditionPublished = 0;
             }
             notifyIfacesChanged();
+            // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
+            // by other networks that are already connected. Perhaps that can be done by
+            // sending all CALLBACK_LOST messages (for requests, not listens) at the end
+            // of rematchAllNetworksAndRequests
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
             mNetworkAgentInfos.remove(msg.replyTo);
@@ -2250,7 +2254,7 @@
                     //    is currently satisfying the request.  This is desirable when
                     //    cellular ends up validating but WiFi does not.
                     // 2. Unvalidated WiFi will not be reaped when validated cellular
-                    //    is currently satsifying the request.  This is desirable when
+                    //    is currently satisfying the request.  This is desirable when
                     //    WiFi ends up validating and out scoring cellular.
                     mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
                             nai.getCurrentScoreAsValidated())) {
@@ -3795,10 +3799,10 @@
 
         // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
         // satisfies mDefaultRequest.
-        NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
+        final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
                 linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest);
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
         synchronized (this) {
             nai.networkMonitor.systemReady = mSystemReady;
         }
@@ -4192,8 +4196,9 @@
         ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
         if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-            NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
-            if (newNetwork == currentNetwork) {
+            final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+            final boolean satisfies = newNetwork.satisfies(nri.request);
+            if (newNetwork == currentNetwork && satisfies) {
                 if (VDBG) {
                     log("Network " + newNetwork.name() + " was already satisfying" +
                             " request " + nri.request.requestId + ". No change.");
@@ -4204,7 +4209,7 @@
 
             // check if it satisfies the NetworkCapabilities
             if (VDBG) log("  checking if request is satisfied: " + nri.request);
-            if (newNetwork.satisfies(nri.request)) {
+            if (satisfies) {
                 if (!nri.isRequest) {
                     // This is not a request, it's a callback listener.
                     // Add it to newNetwork regardless of score.
@@ -4247,6 +4252,37 @@
                         oldDefaultNetwork = currentNetwork;
                     }
                 }
+            } else if (newNetwork.networkRequests.get(nri.request.requestId) != null) {
+                // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
+                // mark it as no longer satisfying "nri".  Because networks are processed by
+                // rematchAllNetworkAndRequests() in descending score order, "currentNetwork" will
+                // match "newNetwork" before this loop will encounter a "currentNetwork" with higher
+                // score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
+                // This means this code doesn't have to handle the case where "currentNetwork" no
+                // longer satisfies "nri" when "currentNetwork" does not equal "newNetwork".
+                if (DBG) {
+                    log("Network " + newNetwork.name() + " stopped satisfying" +
+                            " request " + nri.request.requestId);
+                }
+                newNetwork.networkRequests.remove(nri.request.requestId);
+                if (currentNetwork == newNetwork) {
+                    mNetworkForRequestId.remove(nri.request.requestId);
+                    sendUpdatedScoreToFactories(nri.request, 0);
+                } else {
+                    if (nri.isRequest == true) {
+                        Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
+                                newNetwork.name() +
+                                " without updating mNetworkForRequestId or factories!");
+                    }
+                }
+                // TODO: technically, sending CALLBACK_LOST here is
+                // incorrect if nri is a request (not a listen) and there
+                // is a replacement network currently connected that can
+                // satisfy it. However, the only capability that can both
+                // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
+                // so this code is only incorrect for a network that loses
+                // the TRUSTED capability, which is a rare case.
+                callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST);
             }
         }
         // Linger any networks that are no longer needed.
@@ -4265,41 +4301,41 @@
                 unlinger(nai);
             }
         }
+        if (isNewDefault) {
+            // Notify system services that this network is up.
+            makeDefault(newNetwork);
+            synchronized (ConnectivityService.this) {
+                // have a new default network, release the transition wakelock in
+                // a second if it's held.  The second pause is to allow apps
+                // to reconnect over the new network
+                if (mNetTransitionWakeLock.isHeld()) {
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                            EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
+                            mNetTransitionWakeLockSerialNumber, 0),
+                            1000);
+                }
+            }
+        }
+
+        // do this after the default net is switched, but
+        // before LegacyTypeTracker sends legacy broadcasts
+        for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
+
+        if (isNewDefault) {
+            // Maintain the illusion: since the legacy API only
+            // understands one network at a time, we must pretend
+            // that the current default network disconnected before
+            // the new one connected.
+            if (oldDefaultNetwork != null) {
+                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
+                                          oldDefaultNetwork, true);
+            }
+            mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
+            mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
+            notifyLockdownVpn(newNetwork);
+        }
+
         if (keep) {
-            if (isNewDefault) {
-                // Notify system services that this network is up.
-                makeDefault(newNetwork);
-                synchronized (ConnectivityService.this) {
-                    // have a new default network, release the transition wakelock in
-                    // a second if it's held.  The second pause is to allow apps
-                    // to reconnect over the new network
-                    if (mNetTransitionWakeLock.isHeld()) {
-                        mHandler.sendMessageDelayed(mHandler.obtainMessage(
-                                EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
-                                mNetTransitionWakeLockSerialNumber, 0),
-                                1000);
-                    }
-                }
-            }
-
-            // do this after the default net is switched, but
-            // before LegacyTypeTracker sends legacy broadcasts
-            for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
-
-            if (isNewDefault) {
-                // Maintain the illusion: since the legacy API only
-                // understands one network at a time, we must pretend
-                // that the current default network disconnected before
-                // the new one connected.
-                if (oldDefaultNetwork != null) {
-                    mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
-                                              oldDefaultNetwork, true);
-                }
-                mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
-                mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
-                notifyLockdownVpn(newNetwork);
-            }
-
             // Notify battery stats service about this network, both the normal
             // interface and any stacked links.
             // TODO: Avoid redoing this; this must only be done once when a network comes online.
@@ -4693,4 +4729,11 @@
             }
         }
     }
+
+    @VisibleForTesting
+    public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
+            NetworkAgentInfo nai, NetworkRequest defaultRequest) {
+        return new NetworkMonitor(context, handler, nai, defaultRequest);
+    }
+
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8a79430..39333f6 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -30,6 +30,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.AsyncChannel;
+import com.android.server.ConnectivityService;
 import com.android.server.connectivity.NetworkMonitor;
 
 import java.util.ArrayList;
@@ -51,7 +52,7 @@
 //    ConnectivityService will tell netd to create the network and immediately transition to
 //    state #3.
 // 3. registered, created, connected, unvalidated
-//    If this network can satsify the default NetworkRequest, then NetworkMonitor will
+//    If this network can satisfy the default NetworkRequest, then NetworkMonitor will
 //    probe for Internet connectivity.
 //    If this network cannot satisfy the default NetworkRequest, it will immediately be
 //    transitioned to state #4.
@@ -164,7 +165,7 @@
 
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
-            NetworkMisc misc, NetworkRequest defaultRequest) {
+            NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = net;
@@ -172,7 +173,7 @@
         linkProperties = lp;
         networkCapabilities = nc;
         currentScore = score;
-        networkMonitor = new NetworkMonitor(context, handler, this, defaultRequest);
+        networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
         networkMisc = misc;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 952ba08..5108564 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -349,7 +349,7 @@
     // Being in the ValidatedState State indicates a Network is:
     // - Successfully validated, or
     // - Wanted "as is" by the user, or
-    // - Does not satsify the default NetworkRequest and so validation has been skipped.
+    // - Does not satisfy the default NetworkRequest and so validation has been skipped.
     private class ValidatedState extends State {
         @Override
         public void enter() {
@@ -558,7 +558,7 @@
 
     // Being in the LingeringState State indicates a Network's validated bit is true and it once
     // was the highest scoring Network satisfying a particular NetworkRequest, but since then
-    // another Network satsified the NetworkRequest with a higher score and hence this Network
+    // another Network satisfied the NetworkRequest with a higher score and hence this Network
     // is "lingered" for a fixed period of time before it is disconnected.  This period of time
     // allows apps to wrap up communication and allows for seamless reactivation if the other
     // higher scoring Network happens to disconnect.
@@ -633,7 +633,8 @@
      * Do a URL fetch on a known server to see if we get the data we expect.
      * Returns HTTP response code.
      */
-    private int isCaptivePortal() {
+    @VisibleForTesting
+    protected int isCaptivePortal() {
         if (!mIsCaptivePortalCheckEnabled) return 204;
 
         HttpURLConnection urlConnection = null;
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 6278371..669b8e5 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -634,6 +634,7 @@
                     && doesPackageSupportRuntimePermissions(carrierPackage)) {
                 grantRuntimePermissionsLPw(carrierPackage, PHONE_PERMISSIONS, userId);
                 grantRuntimePermissionsLPw(carrierPackage, LOCATION_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(carrierPackage, SMS_PERMISSIONS, userId);
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index cb9c6a76..3618e1a 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -81,6 +81,7 @@
 import android.util.Log;
 import android.util.LogPrinter;
 
+import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
 
 import org.mockito.ArgumentCaptor;
@@ -118,7 +119,7 @@
     private INetworkPolicyManager mPolicyService;
 
     private BroadcastInterceptingContext mServiceContext;
-    private ConnectivityService mService;
+    private WrappedConnectivityService mService;
     private ConnectivityManager mCm;
     private MockNetworkAgent mWiFiNetworkAgent;
     private MockNetworkAgent mCellNetworkAgent;
@@ -148,6 +149,7 @@
     }
 
     private class MockNetworkAgent {
+        private final WrappedNetworkMonitor mWrappedNetworkMonitor;
         private final NetworkInfo mNetworkInfo;
         private final NetworkCapabilities mNetworkCapabilities;
         private final Thread mThread;
@@ -172,6 +174,7 @@
                     throw new UnsupportedOperationException("unimplemented network type");
             }
             final ConditionVariable initComplete = new ConditionVariable();
+            final ConditionVariable networkMonitorAvailable = mService.getNetworkMonitorCreatedCV();
             mThread = new Thread() {
                 public void run() {
                     Looper.prepare();
@@ -186,6 +189,8 @@
             };
             mThread.start();
             waitFor(initComplete);
+            waitFor(networkMonitorAvailable);
+            mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
         }
 
         public void adjustScore(int change) {
@@ -211,44 +216,46 @@
             assertEquals(mNetworkInfo.getDetailedState(), DetailedState.IDLE);
             assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
 
-            // To pretend network is validated, we transition it to the CONNECTED state without
-            // NET_CAPABILITY_INTERNET so NetworkMonitor doesn't bother trying to validate and
-            // just rubber stamps it as validated.  Afterwards we add NET_CAPABILITY_INTERNET so
-            // the network can satisfy the default request.
             NetworkCallback callback = null;
             final ConditionVariable validatedCv = new ConditionVariable();
             if (validated) {
-                // If we connect a network without INTERNET capability, it'll get reaped.
-                // Prevent the reaping by adding a NetworkRequest.
+                mWrappedNetworkMonitor.gen204ProbeResult = 204;
                 NetworkRequest request = new NetworkRequest.Builder()
                         .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
                         .build();
                 callback = new NetworkCallback() {
                     public void onCapabilitiesChanged(Network network,
                             NetworkCapabilities networkCapabilities) {
-                        if (networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+                        if (network.equals(getNetwork()) &&
+                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                             validatedCv.open();
                         }
                     }
                 };
-                mCm.requestNetwork(request, callback);
-            } else {
-                mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
-                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+                mCm.registerNetworkCallback(request, callback);
             }
+            addCapability(NET_CAPABILITY_INTERNET);
 
             connectWithoutInternet();
 
             if (validated) {
                 // Wait for network to validate.
                 waitFor(validatedCv);
-                mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
-                mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+                mWrappedNetworkMonitor.gen204ProbeResult = 500;
             }
 
             if (callback != null) mCm.unregisterNetworkCallback(callback);
         }
 
+        public void connectWithCaptivePortal() {
+            mWrappedNetworkMonitor.gen204ProbeResult = 200;
+            connect(false);
+            waitFor(new Criteria() { public boolean get() {
+                NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork());
+                return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} });
+            mWrappedNetworkMonitor.gen204ProbeResult = 500;
+        }
+
         public void disconnect() {
             mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -261,14 +268,18 @@
         public ConditionVariable getDisconnectedCV() {
             return mDisconnected;
         }
+
+        public WrappedNetworkMonitor getWrappedNetworkMonitor() {
+            return mWrappedNetworkMonitor;
+        }
     }
 
     private static class MockNetworkFactory extends NetworkFactory {
-        final ConditionVariable mNetworkStartedCV = new ConditionVariable();
-        final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
-        final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
-        final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
-        final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
+        private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
+        private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
+        private final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
+        private final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
+        private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
 
         public MockNetworkFactory(Looper looper, Context context, String logTag,
                 NetworkCapabilities filter) {
@@ -328,7 +339,26 @@
         }
     }
 
+    // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
+    private class WrappedNetworkMonitor extends NetworkMonitor {
+        // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
+        public int gen204ProbeResult = 500;
+
+        public WrappedNetworkMonitor(Context context, Handler handler,
+            NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) {
+            super(context, handler, networkAgentInfo, defaultRequest);
+        }
+
+        @Override
+        protected int isCaptivePortal() {
+            return gen204ProbeResult;
+        }
+    }
+
     private class WrappedConnectivityService extends ConnectivityService {
+        private final ConditionVariable mNetworkMonitorCreated = new ConditionVariable();
+        private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
+
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
                 INetworkStatsService statsService, INetworkPolicyManager policyManager) {
             super(context, netManager, statsService, policyManager);
@@ -360,6 +390,25 @@
                 return netId;
             }
         }
+
+        @Override
+        public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
+                NetworkAgentInfo nai, NetworkRequest defaultRequest) {
+            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(context, handler, nai,
+                    defaultRequest);
+            mLastCreatedNetworkMonitor = monitor;
+            mNetworkMonitorCreated.open();
+            return monitor;
+        }
+
+        public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
+            return mLastCreatedNetworkMonitor;
+        }
+
+        public ConditionVariable getNetworkMonitorCreatedCV() {
+            mNetworkMonitorCreated.close();
+            return mNetworkMonitorCreated;
+        }
     }
 
     private interface Criteria {
@@ -586,29 +635,29 @@
 
     @LargeTest
     public void testUnlingeringDoesNotValidate() throws Exception {
-        // Test bringing up unvalidated cellular.
-        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
-        ConditionVariable cv = waitForConnectivityBroadcasts(1);
-        mCellNetworkAgent.connect(false);
-        waitFor(cv);
-        verifyActiveNetwork(TRANSPORT_CELLULAR);
-        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
-                NET_CAPABILITY_VALIDATED));
-        // Test bringing up validated WiFi.
+        // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        cv = waitForConnectivityBroadcasts(2);
-        mWiFiNetworkAgent.connect(true);
+        ConditionVariable cv = waitForConnectivityBroadcasts(1);
+        mWiFiNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
-        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
-        // Test WiFi disconnect.
+        // Test bringing up validated cellular.
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         cv = waitForConnectivityBroadcasts(2);
-        mWiFiNetworkAgent.disconnect();
+        mCellNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
+        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
+                NET_CAPABILITY_VALIDATED));
+        // Test cellular disconnect.
+        cv = waitForConnectivityBroadcasts(2);
+        mCellNetworkAgent.disconnect();
+        waitFor(cv);
+        verifyActiveNetwork(TRANSPORT_WIFI);
         // Unlingering a network should not cause it to be marked as validated.
-        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
+        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
     }
 
@@ -846,12 +895,8 @@
 
         cellCv = cellNetworkCallback.getConditionVariable();
         wifiCv = wifiNetworkCallback.getConditionVariable();
-        // Our method for faking successful validation generates an additional callback, so wait
-        // for broadcast instead.
-        cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
         waitFor(cellCv);
         assertEquals(CallbackState.AVAILABLE, cellNetworkCallback.getLastCallback());
         assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
@@ -868,12 +913,8 @@
 
         cellCv = cellNetworkCallback.getConditionVariable();
         wifiCv = wifiNetworkCallback.getConditionVariable();
-        // Our method for faking successful validation generates an additional callback, so wait
-        // for broadcast instead.
-        cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
         waitFor(wifiCv);
         assertEquals(CallbackState.AVAILABLE, wifiNetworkCallback.getLastCallback());
         waitFor(cellCv);
@@ -1075,6 +1116,63 @@
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
+    @LargeTest
+    public void testCaptivePortal() {
+        final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
+        final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
+        mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
+
+        final TestNetworkCallback validatedCallback = new TestNetworkCallback();
+        final NetworkRequest validatedRequest = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_VALIDATED).build();
+        mCm.registerNetworkCallback(validatedRequest, validatedCallback);
+        ConditionVariable validatedCv = validatedCallback.getConditionVariable();
+
+        // Bring up a network with a captive portal.
+        // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
+        ConditionVariable cv = captivePortalCallback.getConditionVariable();
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connectWithCaptivePortal();
+        waitFor(cv);
+        assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());
+
+        // Take down network.
+        // Expect onLost callback.
+        cv = captivePortalCallback.getConditionVariable();
+        mWiFiNetworkAgent.disconnect();
+        waitFor(cv);
+        assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());
+
+        // Bring up a network with a captive portal.
+        // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
+        cv = captivePortalCallback.getConditionVariable();
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connectWithCaptivePortal();
+        waitFor(cv);
+        assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());
+
+        // Make captive portal disappear then revalidate.
+        // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
+        cv = captivePortalCallback.getConditionVariable();
+        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
+        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
+        waitFor(cv);
+        assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());
+
+        // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
+        waitFor(validatedCv);
+        assertEquals(CallbackState.AVAILABLE, validatedCallback.getLastCallback());
+
+        // Break network connectivity.
+        // Expect NET_CAPABILITY_VALIDATED onLost callback.
+        validatedCv = validatedCallback.getConditionVariable();
+        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
+        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
+        waitFor(validatedCv);
+        assertEquals(CallbackState.LOST, validatedCallback.getLastCallback());
+    }
+
 //    @Override
 //    public void tearDown() throws Exception {
 //        super.tearDown();
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 97bf505..38ede87 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -128,7 +128,7 @@
             mReceiver = receiver;
         }
     }
-    
+
     public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
         // FIXME - support devices with different number of input and output ports
         int subDeviceCount = nativeGetSubdeviceCount(card, device);
@@ -203,6 +203,8 @@
                 byte[] buffer = new byte[BUFFER_SIZE];
                 try {
                     while (true) {
+                        // Record time of event immediately after waking.
+                        long timestamp = System.nanoTime();
                         synchronized (mLock) {
                             if (!mIsOpen) break;
 
@@ -215,14 +217,14 @@
                                 } else if ((pfd.revents & OsConstants.POLLIN) != 0) {
                                     // clear readable flag
                                     pfd.revents = 0;
-                                    
+
                                     if (index == mInputStreams.length - 1) {
                                         // last file descriptor is used only for unblocking Os.poll()
                                         break;
                                     }
 
                                     int count = mInputStreams[index].read(buffer);
-                                    outputReceivers[index].send(buffer, 0, count);
+                                    outputReceivers[index].send(buffer, 0, count, timestamp);
                                 }
                             }
                         }