Merge "Add VisualVoicemailService"
diff --git a/api/current.txt b/api/current.txt
index ddb42b9..8894f97 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7078,6 +7078,7 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+    method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method public boolean createBond();
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
@@ -38228,6 +38229,7 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public void setDataEnabled(boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 503e897..3a3ba96 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7381,6 +7381,7 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+    method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method public boolean createBond();
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
@@ -41453,6 +41454,7 @@
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method public void setDataEnabled(boolean);
     method public void setDataEnabled(int, boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index 3b4fabe..88b3c2f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -7087,6 +7087,7 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+    method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method public boolean createBond();
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
@@ -38327,6 +38328,7 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public void setDataEnabled(boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e6cebc0..e0b03d2 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -22,6 +22,8 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.ParcelUuid;
@@ -593,32 +595,38 @@
     public static final int TRANSPORT_LE = 2;
 
     /**
-     * Bluetooth LE 1M PHY.
+     * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
+     * connection.
      */
     public static final int PHY_LE_1M = 1;
 
     /**
-     * Bluetooth LE 2M PHY.
+     * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
+     * connection.
      */
     public static final int PHY_LE_2M = 2;
 
     /**
-     * Bluetooth LE Coded PHY.
+     * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
+     * or connection.
      */
     public static final int PHY_LE_CODED = 3;
 
     /**
-     * Bluetooth LE 1M PHY mask.
+     * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
+     * options in a bitmask.
      */
     public static final int PHY_LE_1M_MASK = 1;
 
     /**
-     * Bluetooth LE 2M PHY mask.
+     * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
+     * options in a bitmask.
      */
     public static final int PHY_LE_2M_MASK = 2;
 
     /**
-     * Bluetooth LE Coded PHY mask.
+     * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
+     * available options in a bitmask.
      */
     public static final int PHY_LE_CODED_MASK = 4;
 
@@ -1679,12 +1687,45 @@
      *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
      *             {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
-     *             and {@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if
-     *             {@code autoConnect} is set to true.
-     * @throws IllegalArgumentException if callback is null
+     *             and {@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
+     *             if {@code autoConnect} is set to true.
+     * @throws NullPointerException if callback is null
      */
     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
                                      BluetoothGattCallback callback, int transport, int phy) {
+        return connectGatt(context, autoConnect,callback, TRANSPORT_AUTO, PHY_LE_1M_MASK, null);
+    }
+
+    /**
+     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as any further GATT client operations.
+     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+     * GATT client operations.
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param autoConnect Whether to directly connect to the remote device (false)
+     *                    or to automatically connect as soon as the remote
+     *                    device becomes available (true).
+     * @param transport preferred transport for GATT connections to remote dual-mode devices
+     *             {@link BluetoothDevice#TRANSPORT_AUTO} or
+     *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+     * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
+     *             {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
+     *             an d{@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
+     *             if {@code autoConnect} is set to true.
+     * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
+     *             on the service's main thread.
+     * @throws NullPointerException if callback is null
+     */
+    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+                                     BluetoothGattCallback callback, int transport, int phy,
+                                     Handler handler) {
+        if (callback == null)
+            throw new NullPointerException("callback is null");
+
+        if (handler == null)
+            handler = new Handler(Looper.getMainLooper());
+
         // TODO(Bluetooth) check whether platform support BLE
         //     Do the check here or in GattServer?
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1696,7 +1737,7 @@
                 return null;
             }
             BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, phy);
-            gatt.connect(autoConnect, callback);
+            gatt.connect(autoConnect, callback, handler);
             return gatt;
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 9144ae7..7806e31 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.content.Context;
+import android.os.Handler;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.util.Log;
@@ -43,6 +44,7 @@
 
     private IBluetoothGatt mService;
     private BluetoothGattCallback mCallback;
+    private Handler mHandler;
     private int mClientIf;
     private BluetoothDevice mDevice;
     private boolean mAutoConnect;
@@ -154,8 +156,14 @@
                 }
                 mClientIf = clientIf;
                 if (status != GATT_SUCCESS) {
-                    mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
-                                                      BluetoothProfile.STATE_DISCONNECTED);
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
+                                              BluetoothProfile.STATE_DISCONNECTED);
+                        }
+                    });
+
                     synchronized(mStateLock) {
                         mConnState = CONN_STATE_IDLE;
                     }
@@ -181,11 +189,12 @@
                     return;
                 }
 
-                try {
-                    mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
+                    }
+                });
             }
 
             /**
@@ -200,11 +209,12 @@
                     return;
                 }
 
-                try {
-                    mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
+                    }
+                });
             }
 
             /**
@@ -221,11 +231,13 @@
                 }
                 int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
                                                BluetoothProfile.STATE_DISCONNECTED;
-                try {
-                    mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
+                    }
+                });
 
                 synchronized(mStateLock) {
                     if (connected) {
@@ -279,11 +291,12 @@
                     }
                 }
 
-                try {
-                    mCallback.onServicesDiscovered(BluetoothGatt.this, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onServicesDiscovered(BluetoothGatt.this, status);
+                    }
+                });
             }
 
             /**
@@ -328,11 +341,12 @@
 
                 if (status == 0) characteristic.setValue(value);
 
-                try {
-                    mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
+                    }
+                });
             }
 
             /**
@@ -373,11 +387,12 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                try {
-                    mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
+                    }
+                });
             }
 
             /**
@@ -398,11 +413,12 @@
 
                 characteristic.setValue(value);
 
-                try {
-                    mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
+                    }
+                });
             }
 
             /**
@@ -442,11 +458,12 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                try {
-                    mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
+                    }
+                });
             }
 
             /**
@@ -485,11 +502,12 @@
 
                 mAuthRetryState = AUTH_RETRY_STATE_IDLE;
 
-                try {
-                    mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
+                    }
+                });
             }
 
             /**
@@ -508,11 +526,12 @@
                     mDeviceBusy = false;
                 }
 
-                try {
-                    mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
+                    }
+                });
             }
 
             /**
@@ -526,11 +545,12 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                try {
-                    mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
+                    }
+                });
             }
 
             /**
@@ -544,11 +564,13 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                try {
-                    mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
+                    }
+                });
             }
 
             /**
@@ -564,12 +586,14 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
-                try {
-                    mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
-                                                  timeout, status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception in callback", ex);
-                }
+
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
+                                                      timeout, status);
+                    }
+                });
             }
         };
 
@@ -659,11 +683,12 @@
      * @return If true, the callback will be called to notify success or failure,
      *         false on immediate error
      */
-    private boolean registerApp(BluetoothGattCallback callback) {
+    private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
         if (DBG) Log.d(TAG, "registerApp()");
         if (mService == null) return false;
 
         mCallback = callback;
+        mHandler = handler;
         UUID uuid = UUID.randomUUID();
         if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
 
@@ -716,7 +741,8 @@
      *                    device becomes available (true).
      * @return true, if the connection attempt was initiated successfully
      */
-    /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
+    /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
+                                Handler handler) {
         if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
         synchronized(mStateLock) {
             if (mConnState != CONN_STATE_IDLE) {
@@ -727,7 +753,7 @@
 
         mAutoConnect = autoConnect;
 
-        if (!registerApp(callback)) {
+        if (!registerApp(callback, handler)) {
             synchronized(mStateLock) {
                 mConnState = CONN_STATE_IDLE;
             }
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 11a15c6..c6f82ff 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -30,7 +30,8 @@
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
      * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
-     * @param status status of the operation
+     * @param status Status of the PHY update operation.
+     *                  {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
      */
     public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
     }
@@ -43,7 +44,8 @@
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
      * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
-     * @param status status of the operation
+     * @param status Status of the PHY read operation.
+     *                  {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
      */
     public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
     }
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index 3b8f962..02307bd 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -167,7 +167,8 @@
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
      * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
-     * @param status status of the operation
+     * @param status Status of the PHY update operation.
+     *                  {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
      */
     public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) {
     }
@@ -180,7 +181,8 @@
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
      * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
      *             {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
-     * @param status status of the operation
+     * @param status Status of the PHY read operation.
+     *                  {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
      */
     public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) {
     }
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 87a2b05..9ce2a5b 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -33,4 +33,20 @@
      * @hide
      */
     public abstract boolean satisfiedBy(NetworkSpecifier other);
+
+    /**
+     * Optional method which can be overriden by concrete implementations of NetworkSpecifier to
+     * check a self-reported UID. A concrete implementation may contain a UID which would be self-
+     * reported by the caller (since NetworkSpecifier implementations should be non-mutable). This
+     * function is called by ConnectivityService and is passed the actual UID of the caller -
+     * allowing the verification of the self-reported UID. In cases of mismatch the implementation
+     * should throw a SecurityException.
+     *
+     * @param requestorUid The UID of the requestor as obtained from its binder.
+     *
+     * @hide
+     */
+    public void assertValidFromUid(int requestorUid) {
+        // empty
+    }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 616a8c0..88bc54d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -49,7 +49,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.PacketKeepalive;
@@ -70,6 +69,7 @@
 import android.net.NetworkMisc;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.Proxy;
@@ -110,7 +110,6 @@
 import android.util.LocalLog;
 import android.util.LocalLog.ReadOnlyLocalLog;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -4131,6 +4130,18 @@
                 0, 0, thresholds);
     }
 
+    private void ensureValidNetworkSpecifier(NetworkCapabilities nc) {
+        if (nc == null) {
+            return;
+        }
+        NetworkSpecifier ns = nc.getNetworkSpecifier();
+        if (ns == null) {
+            return;
+        }
+        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(ns);
+        ns.assertValidFromUid(Binder.getCallingUid());
+    }
+
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
             Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
@@ -4156,9 +4167,7 @@
         if (timeoutMs < 0) {
             throw new IllegalArgumentException("Bad timeout specified");
         }
-
-        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
-                networkCapabilities.getNetworkSpecifier());
+        ensureValidNetworkSpecifier(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId(), type);
@@ -4230,9 +4239,7 @@
         enforceNetworkRequestPermissions(networkCapabilities);
         enforceMeteredApnPolicy(networkCapabilities);
         ensureRequestableCapabilities(networkCapabilities);
-
-        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
-                networkCapabilities.getNetworkSpecifier());
+        ensureValidNetworkSpecifier(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
                 nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4294,9 +4301,7 @@
             // can't request networks.
             nc.addCapability(NET_CAPABILITY_FOREGROUND);
         }
-
-        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
-                networkCapabilities.getNetworkSpecifier());
+        ensureValidNetworkSpecifier(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
@@ -4314,9 +4319,7 @@
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
         }
-
-        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
-                networkCapabilities.getNetworkSpecifier());
+        ensureValidNetworkSpecifier(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(
                 new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fb07478..5d222d4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5037,32 +5037,46 @@
 
     /* <p>Requires permission:
      * @link android.Manifest.permission#CALL_PHONE}
+     * @param ussdRequest the USSD command to be executed.
+     * @param wrappedCallback receives a callback result.
      */
     @RequiresPermission(android.Manifest.permission.CALL_PHONE)
     public void sendUssdRequest(String ussdRequest,
                                 final OnReceiveUssdResponseCallback callback, Handler handler) {
-       checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null.");
+        sendUssdRequest(ussdRequest, getSubId(), callback, handler);
+    }
 
-       ResultReceiver wrappedCallback = new ResultReceiver(handler) {
-           @Override
-           protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
-              Rlog.d(TAG, "USSD:" + resultCode);
-              checkNotNull(ussdResponse, "ussdResponse cannot be null.");
-              UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE);
+   /* <p>Requires permission:
+    * @link android.Manifest.permission#CALL_PHONE}
+    * @param subId The subscription to use.
+    * @param ussdRequest the USSD command to be executed.
+    * @param wrappedCallback receives a callback result.
+    */
+    @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+    public void sendUssdRequest(String ussdRequest, int subId,
+                                final OnReceiveUssdResponseCallback callback, Handler handler) {
+        checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null.");
 
-              if (resultCode == USSD_RETURN_SUCCESS) {
-                 callback.onReceiveUssdResponse(response.getUssdRequest(),
-                         response.getReturnMessage());
-              } else {
-                 callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode);
-              }
-           }
+        ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
+                Rlog.d(TAG, "USSD:" + resultCode);
+                checkNotNull(ussdResponse, "ussdResponse cannot be null.");
+                UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE);
+
+                if (resultCode == USSD_RETURN_SUCCESS) {
+                    callback.onReceiveUssdResponse(response.getUssdRequest(),
+                            response.getReturnMessage());
+                } else {
+                    callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode);
+                }
+            }
         };
 
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                telephony.handleUssdRequest(ussdRequest, wrappedCallback);
+                telephony.handleUssdRequest(subId, ussdRequest, wrappedCallback);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#sendUSSDCode", e);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2be0597..6b9c81d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -278,10 +278,11 @@
     /**
      * Handles USSD commands.
      *
+     * @param subId The subscription to use.
      * @param ussdRequest the USSD command to be executed.
      * @param wrappedCallback receives a callback result.
      */
-    void handleUssdRequest(String ussdRequest, in ResultReceiver wrappedCallback);
+    void handleUssdRequest(int subId, String ussdRequest, in ResultReceiver wrappedCallback);
 
     /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1be8d5e..5173278 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1993,6 +1993,40 @@
     }
 
     @SmallTest
+    public void testNetworkSpecifierUidSpoofSecurityException() {
+        class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+            @Override
+            public boolean satisfiedBy(NetworkSpecifier other) {
+                return true;
+            }
+
+            @Override
+            public void assertValidFromUid(int requestorUid) {
+                throw new SecurityException("failure");
+            }
+
+            @Override
+            public int describeContents() { return 0; }
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {}
+        }
+
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+
+        UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
+        NetworkRequest networkRequest = newWifiRequestBuilder().setNetworkSpecifier(
+                networkSpecifier).build();
+        TestNetworkCallback networkCallback = new TestNetworkCallback();
+        try {
+            mCm.requestNetwork(networkRequest, networkCallback);
+            fail("Network request with spoofed UID did not throw a SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @SmallTest
     public void testRegisterDefaultNetworkCallback() throws Exception {
         final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 3fcbd4b..b9ce61c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -31,6 +31,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.SparseArray;
@@ -453,7 +454,8 @@
                 peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID
                 null, // peerMac (not used in this method)
                 pmk,
-                passphrase);
+                passphrase,
+                Process.myUid());
     }
 
     /** @hide */
@@ -490,7 +492,8 @@
                 0, // 0 is an invalid peer ID
                 peer,
                 pmk,
-                passphrase);
+                passphrase,
+                Process.myUid());
     }
 
     private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 5993480..e152f6c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -19,6 +19,7 @@
 import android.net.NetworkSpecifier;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -115,9 +116,18 @@
      */
     public final String passphrase;
 
+    /**
+     * The UID of the process initializing this network specifier. Validated by receiver using
+     * checkUidIfNecessary() and is used by satisfiedBy() to determine whether matches the
+     * offered network.
+     *
+     * @hide
+     */
+    public final int requestorUid;
+
     /** @hide */
     public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId,
-            byte[] peerMac, byte[] pmk, String passphrase) {
+            byte[] peerMac, byte[] pmk, String passphrase, int requestorUid) {
         this.type = type;
         this.role = role;
         this.clientId = clientId;
@@ -126,6 +136,7 @@
         this.peerMac = peerMac;
         this.pmk = pmk;
         this.passphrase = passphrase;
+        this.requestorUid = requestorUid;
     }
 
     public static final Creator<WifiAwareNetworkSpecifier> CREATOR =
@@ -140,7 +151,8 @@
                         in.readInt(), // peerId
                         in.createByteArray(), // peerMac
                         in.createByteArray(), // pmk
-                        in.readString()); // passphrase
+                        in.readString(), // passphrase
+                        in.readInt()); // requestorUid
                 }
 
                 @Override
@@ -164,6 +176,7 @@
         dest.writeByteArray(peerMac);
         dest.writeByteArray(pmk);
         dest.writeString(passphrase);
+        dest.writeInt(requestorUid);
     }
 
     /** @hide */
@@ -186,6 +199,7 @@
         result = 31 * result + Arrays.hashCode(peerMac);
         result = 31 * result + Arrays.hashCode(pmk);
         result = 31 * result + Objects.hashCode(passphrase);
+        result = 31 * result + requestorUid;
 
         return result;
     }
@@ -210,7 +224,8 @@
                 && peerId == lhs.peerId
                 && Arrays.equals(peerMac, lhs.peerMac)
                 && Arrays.equals(pmk, lhs.pmk)
-                && Objects.equals(passphrase, lhs.passphrase);
+                && Objects.equals(passphrase, lhs.passphrase)
+                && requestorUid == lhs.requestorUid;
     }
 
     /** @hide */
@@ -228,7 +243,16 @@
                 .append(", pmk=").append((pmk == null) ? "<null>" : "<non-null>")
                 // masking PII
                 .append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>")
+                .append(", requestorUid=").append(requestorUid)
                 .append("]");
         return sb.toString();
     }
+
+    /** @hide */
+    @Override
+    public void assertValidFromUid(int requestorUid) {
+        if (this.requestorUid != requestorUid) {
+            throw new SecurityException("mismatched UIDs");
+        }
+    }
 }