Merge "More time zone update API classes"
diff --git a/Android.mk b/Android.mk
index 283e9dc..02caa0a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -132,7 +132,6 @@
 	core/java/android/bluetooth/IBluetoothGatt.aidl \
 	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
 	core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
-	core/java/android/bluetooth/le/IAdvertiserCallback.aidl \
 	core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl \
 	core/java/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl \
 	core/java/android/bluetooth/le/IScannerCallback.aidl \
@@ -406,6 +405,7 @@
 	media/java/android/media/projection/IMediaProjectionManager.aidl \
 	media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \
 	media/java/android/media/session/IActiveSessionsListener.aidl \
+	media/java/android/media/session/ICallback.aidl \
 	media/java/android/media/session/ISessionController.aidl \
 	media/java/android/media/session/ISessionControllerCallback.aidl \
 	media/java/android/media/session/ISession.aidl \
@@ -434,6 +434,12 @@
 	telecomm/java/com/android/internal/telecom/IInCallService.aidl \
 	telecomm/java/com/android/internal/telecom/ITelecomService.aidl \
 	telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl \
+        telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl \
+	telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl \
+	telephony/java/android/telephony/mbms/IDownloadCallback.aidl \
+        telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl \
+	telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl \
+	telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl \
 	telephony/java/com/android/ims/internal/IImsCallSession.aidl \
 	telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl \
 	telephony/java/com/android/ims/internal/IImsConfig.aidl \
@@ -542,6 +548,13 @@
 include $(CLEAR_VARS)
 
 aidl_files := \
+        frameworks/base/telephony/java/android/telephony/mbms/DownloadRequest.aidl \
+        frameworks/base/telephony/java/android/telephony/mbms/DownloadStatus.aidl \
+        frameworks/base/telephony/java/android/telephony/mbms/FileInfo.aidl \
+        frameworks/base/telephony/java/android/telephony/mbms/FileServiceInfo.aidl \
+        frameworks/base/telephony/java/android/telephony/mbms/ServiceInfo.aidl \
+	frameworks/base/telephony/java/android/telephony/mbms/StreamingService.aidl \
+        frameworks/base/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
 	frameworks/base/telephony/java/android/telephony/SubscriptionInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/CellInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index 00b6986..3ba7f8f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36,6 +36,7 @@
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+    field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -7077,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;
@@ -7501,7 +7503,7 @@
     method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
     method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
     method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
-    method public void setPeriodicAdvertisingEnable(boolean);
+    method public void setPeriodicAdvertisingEnabled(boolean);
     method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
     method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
   }
@@ -7671,8 +7673,10 @@
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
     field public static final int DATA_COMPLETE = 0; // 0x0
     field public static final int DATA_TRUNCATED = 2; // 0x2
+    field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
     field public static final int PHY_UNUSED = 0; // 0x0
     field public static final int SID_NOT_PRESENT = 255; // 0xff
+    field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
   }
 
   public final class ScanSettings implements android.os.Parcelable {
@@ -8318,7 +8322,6 @@
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
-    field public static final java.lang.String IPSEC_SERVICE = "ipsec";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
     field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
     field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -18179,9 +18182,9 @@
     method protected final void computeGregorianFields(int);
     method protected int computeGregorianMonthStart(int, int);
     method protected int computeJulianDay();
-    method protected int computeMillisInDay();
+    method protected deprecated int computeMillisInDay();
     method protected void computeTime();
-    method protected int computeZoneOffset(long, int);
+    method protected deprecated int computeZoneOffset(long, int);
     method public int fieldDifference(java.util.Date, int);
     method protected java.lang.String fieldName(int);
     method protected static final long floorDivide(long, long);
@@ -23870,70 +23873,6 @@
     field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
   }
 
-  public final class IpSecAlgorithm implements android.os.Parcelable {
-    ctor public IpSecAlgorithm(java.lang.String, byte[]);
-    ctor public IpSecAlgorithm(java.lang.String, byte[], int);
-    method public int describeContents();
-    method public byte[] getKey();
-    method public java.lang.String getName();
-    method public int getTruncationLengthBits();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
-    field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
-    field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
-    field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
-    field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
-    field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
-    field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
-  }
-
-  public final class IpSecManager {
-    method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
-    method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
-  }
-
-  public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
-  }
-
-  public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getPort();
-    method public java.io.FileDescriptor getSocket();
-  }
-
-  public final class IpSecTransform implements java.lang.AutoCloseable {
-    method public void close();
-    field public static final int DIRECTION_IN = 0; // 0x0
-    field public static final int DIRECTION_OUT = 1; // 0x1
-  }
-
-  public static class IpSecTransform.Builder {
-    ctor public IpSecTransform.Builder(android.content.Context);
-    method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
-    method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
-  }
-
   public class LinkAddress implements android.os.Parcelable {
     method public int describeContents();
     method public java.net.InetAddress getAddress();
@@ -33654,8 +33593,8 @@
   }
 
   public static final class Telephony.ServiceStateTable {
-    method public static android.net.Uri getUriForSubId(int);
-    method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+    method public static android.net.Uri getUriForSubscriptionId(int);
+    method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
     field public static final java.lang.String AUTHORITY = "service-state";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -33844,6 +33783,8 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    field public static final java.lang.String ARCHIVED = "archived";
+    field public static final java.lang.String BACKED_UP = "backed_up";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -33851,6 +33792,7 @@
     field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String HAS_CONTENT = "has_content";
+    field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
     field public static final java.lang.String IS_READ = "is_read";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
     field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -33858,6 +33800,7 @@
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final java.lang.String RESTORED = "restored";
     field public static final java.lang.String SOURCE_DATA = "source_data";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
     field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -37110,7 +37053,6 @@
   }
 
   public static final class Connection.RttModifyStatus {
-    ctor public Connection.RttModifyStatus();
     field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
     field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
     field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
@@ -37592,7 +37534,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
@@ -37676,9 +37619,13 @@
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -38178,7 +38125,6 @@
     method public android.os.PersistableBundle getCarrierConfig();
     method public deprecated android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
-    method public boolean getDataEnabled();
     method public int getDataNetworkType();
     method public int getDataState();
     method public deprecated java.lang.String getDeviceId();
@@ -38210,6 +38156,7 @@
     method public int getSimState();
     method public int getSimState(int);
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getVisualVoicemailPackageName();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public int getVoiceNetworkType();
@@ -38222,6 +38169,8 @@
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public boolean isConcurrentVoiceAndDataAllowed();
+    method public boolean isDataEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
@@ -38231,6 +38180,7 @@
     method public boolean isWorldPhone();
     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 setDataEnabled(boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
@@ -38305,6 +38255,57 @@
     field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
   }
 
+  public static abstract class TelephonyManager.OnReceiveUssdResponseCallback {
+    ctor public TelephonyManager.OnReceiveUssdResponseCallback();
+    method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence);
+    method public void onReceiveUssdResponseFailed(java.lang.String, int);
+  }
+
+  public abstract class VisualVoicemailService extends android.app.Service {
+    ctor public VisualVoicemailService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+    method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+    method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+    method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+  }
+
+  public static class VisualVoicemailService.VisualVoicemailTask {
+    method public final void finish();
+  }
+
+  public final class VisualVoicemailSms implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getFields();
+    method public java.lang.String getMessageBody();
+    method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method public java.lang.String getPrefix();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
+  }
+
+  public final class VisualVoicemailSmsFilterSettings implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
+    field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
+    field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
+    field public final java.lang.String clientPrefix;
+    field public final int destinationPort;
+    field public final java.util.List<java.lang.String> originatingNumbers;
+  }
+
+  public static class VisualVoicemailSmsFilterSettings.Builder {
+    ctor public VisualVoicemailSmsFilterSettings.Builder();
+    method public android.telephony.VisualVoicemailSmsFilterSettings build();
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
+  }
+
 }
 
 package android.telephony.cdma {
@@ -49708,15 +49709,15 @@
     ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
   }
 
-  public final class DexFile {
-    ctor public DexFile(java.io.File) throws java.io.IOException;
-    ctor public DexFile(java.lang.String) throws java.io.IOException;
+  public final deprecated class DexFile {
+    ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
+    ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<java.lang.String> entries();
     method public java.lang.String getName();
     method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
     method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
-    method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+    method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
   public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9eb4599..8623df7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -55,6 +55,7 @@
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
     field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
+    field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -7380,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;
@@ -7806,7 +7808,7 @@
     method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
     method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
     method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
-    method public void setPeriodicAdvertisingEnable(boolean);
+    method public void setPeriodicAdvertisingEnabled(boolean);
     method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
     method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
   }
@@ -7989,8 +7991,10 @@
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
     field public static final int DATA_COMPLETE = 0; // 0x0
     field public static final int DATA_TRUNCATED = 2; // 0x2
+    field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
     field public static final int PHY_UNUSED = 0; // 0x0
     field public static final int SID_NOT_PRESENT = 255; // 0xff
+    field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
   }
 
   public final class ScanSettings implements android.os.Parcelable {
@@ -8653,7 +8657,6 @@
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
-    field public static final java.lang.String IPSEC_SERVICE = "ipsec";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
     field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
     field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -19394,9 +19397,9 @@
     method protected final void computeGregorianFields(int);
     method protected int computeGregorianMonthStart(int, int);
     method protected int computeJulianDay();
-    method protected int computeMillisInDay();
+    method protected deprecated int computeMillisInDay();
     method protected void computeTime();
-    method protected int computeZoneOffset(long, int);
+    method protected deprecated int computeZoneOffset(long, int);
     method public int fieldDifference(java.util.Date, int);
     method protected java.lang.String fieldName(int);
     method protected static final long floorDivide(long, long);
@@ -25708,72 +25711,6 @@
     field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
   }
 
-  public final class IpSecAlgorithm implements android.os.Parcelable {
-    ctor public IpSecAlgorithm(java.lang.String, byte[]);
-    ctor public IpSecAlgorithm(java.lang.String, byte[], int);
-    method public int describeContents();
-    method public byte[] getKey();
-    method public java.lang.String getName();
-    method public int getTruncationLengthBits();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
-    field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
-    field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
-    field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
-    field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
-    field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
-    field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
-  }
-
-  public final class IpSecManager {
-    method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
-    method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
-  }
-
-  public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
-  }
-
-  public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getPort();
-    method public java.io.FileDescriptor getSocket();
-  }
-
-  public final class IpSecTransform implements java.lang.AutoCloseable {
-    method public void close();
-    field public static final int DIRECTION_IN = 0; // 0x0
-    field public static final int DIRECTION_OUT = 1; // 0x1
-  }
-
-  public static class IpSecTransform.Builder {
-    ctor public IpSecTransform.Builder(android.content.Context);
-    method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
-    method public android.net.IpSecTransform.Builder setNattKeepalive(int);
-    method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
-    method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
-  }
-
   public class LinkAddress implements android.os.Parcelable {
     method public int describeContents();
     method public java.net.InetAddress getAddress();
@@ -36498,8 +36435,8 @@
   }
 
   public static final class Telephony.ServiceStateTable {
-    method public static android.net.Uri getUriForSubId(int);
-    method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+    method public static android.net.Uri getUriForSubscriptionId(int);
+    method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
     field public static final java.lang.String AUTHORITY = "service-state";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -36688,6 +36625,8 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    field public static final java.lang.String ARCHIVED = "archived";
+    field public static final java.lang.String BACKED_UP = "backed_up";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -36695,6 +36634,7 @@
     field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String HAS_CONTENT = "has_content";
+    field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
     field public static final java.lang.String IS_READ = "is_read";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
     field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -36702,6 +36642,7 @@
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final java.lang.String RESTORED = "restored";
     field public static final java.lang.String SOURCE_DATA = "source_data";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
     field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -40095,7 +40036,6 @@
   }
 
   public static final class Connection.RttModifyStatus {
-    ctor public Connection.RttModifyStatus();
     field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
     field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
     field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
@@ -40765,7 +40705,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
@@ -40849,9 +40790,13 @@
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -41391,8 +41336,8 @@
     method public int getCurrentPhoneType();
     method public int getCurrentPhoneType(int);
     method public int getDataActivity();
-    method public boolean getDataEnabled();
-    method public boolean getDataEnabled(int);
+    method public deprecated boolean getDataEnabled();
+    method public deprecated boolean getDataEnabled(int);
     method public int getDataNetworkType();
     method public int getDataState();
     method public deprecated java.lang.String getDeviceId();
@@ -41425,6 +41370,7 @@
     method public int getSimState(int);
     method public java.lang.String getSubscriberId();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+    method public java.lang.String getVisualVoicemailPackageName();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public int getVoiceNetworkType();
@@ -41439,7 +41385,9 @@
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public boolean isConcurrentVoiceAndDataAllowed();
     method public boolean isDataConnectivityPossible();
+    method public boolean isDataEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isIdle();
     method public boolean isNetworkRoaming();
@@ -41456,6 +41404,7 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     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 int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method public void setDataEnabled(boolean);
     method public void setDataEnabled(int, boolean);
@@ -41551,6 +41500,57 @@
     field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
   }
 
+  public static abstract class TelephonyManager.OnReceiveUssdResponseCallback {
+    ctor public TelephonyManager.OnReceiveUssdResponseCallback();
+    method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence);
+    method public void onReceiveUssdResponseFailed(java.lang.String, int);
+  }
+
+  public abstract class VisualVoicemailService extends android.app.Service {
+    ctor public VisualVoicemailService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+    method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+    method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+    method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+  }
+
+  public static class VisualVoicemailService.VisualVoicemailTask {
+    method public final void finish();
+  }
+
+  public final class VisualVoicemailSms implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getFields();
+    method public java.lang.String getMessageBody();
+    method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method public java.lang.String getPrefix();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
+  }
+
+  public final class VisualVoicemailSmsFilterSettings implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
+    field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
+    field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
+    field public final java.lang.String clientPrefix;
+    field public final int destinationPort;
+    field public final java.util.List<java.lang.String> originatingNumbers;
+  }
+
+  public static class VisualVoicemailSmsFilterSettings.Builder {
+    ctor public VisualVoicemailSmsFilterSettings.Builder();
+    method public android.telephony.VisualVoicemailSmsFilterSettings build();
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
+  }
+
 }
 
 package android.telephony.cdma {
@@ -53332,15 +53332,15 @@
     ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
   }
 
-  public final class DexFile {
-    ctor public DexFile(java.io.File) throws java.io.IOException;
-    ctor public DexFile(java.lang.String) throws java.io.IOException;
+  public final deprecated class DexFile {
+    ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
+    ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<java.lang.String> entries();
     method public java.lang.String getName();
     method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
     method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
-    method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+    method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
   public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/api/test-current.txt b/api/test-current.txt
index 57e2ed8..2fc87ada 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36,6 +36,7 @@
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+    field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -7086,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;
@@ -7510,7 +7512,7 @@
     method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
     method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
     method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
-    method public void setPeriodicAdvertisingEnable(boolean);
+    method public void setPeriodicAdvertisingEnabled(boolean);
     method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
     method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
   }
@@ -7680,8 +7682,10 @@
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
     field public static final int DATA_COMPLETE = 0; // 0x0
     field public static final int DATA_TRUNCATED = 2; // 0x2
+    field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
     field public static final int PHY_UNUSED = 0; // 0x0
     field public static final int SID_NOT_PRESENT = 255; // 0xff
+    field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
   }
 
   public final class ScanSettings implements android.os.Parcelable {
@@ -8329,7 +8333,6 @@
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
-    field public static final java.lang.String IPSEC_SERVICE = "ipsec";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
     field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
     field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -18197,9 +18200,9 @@
     method protected final void computeGregorianFields(int);
     method protected int computeGregorianMonthStart(int, int);
     method protected int computeJulianDay();
-    method protected int computeMillisInDay();
+    method protected deprecated int computeMillisInDay();
     method protected void computeTime();
-    method protected int computeZoneOffset(long, int);
+    method protected deprecated int computeZoneOffset(long, int);
     method public int fieldDifference(java.util.Date, int);
     method protected java.lang.String fieldName(int);
     method protected static final long floorDivide(long, long);
@@ -23944,70 +23947,6 @@
     field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
   }
 
-  public final class IpSecAlgorithm implements android.os.Parcelable {
-    ctor public IpSecAlgorithm(java.lang.String, byte[]);
-    ctor public IpSecAlgorithm(java.lang.String, byte[], int);
-    method public int describeContents();
-    method public byte[] getKey();
-    method public java.lang.String getName();
-    method public int getTruncationLengthBits();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
-    field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
-    field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
-    field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
-    field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
-    field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
-    field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
-  }
-
-  public final class IpSecManager {
-    method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
-    method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
-  }
-
-  public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
-  }
-
-  public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getPort();
-    method public java.io.FileDescriptor getSocket();
-  }
-
-  public final class IpSecTransform implements java.lang.AutoCloseable {
-    method public void close();
-    field public static final int DIRECTION_IN = 0; // 0x0
-    field public static final int DIRECTION_OUT = 1; // 0x1
-  }
-
-  public static class IpSecTransform.Builder {
-    ctor public IpSecTransform.Builder(android.content.Context);
-    method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
-    method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
-  }
-
   public class LinkAddress implements android.os.Parcelable {
     method public int describeContents();
     method public java.net.InetAddress getAddress();
@@ -33735,8 +33674,8 @@
   }
 
   public static final class Telephony.ServiceStateTable {
-    method public static android.net.Uri getUriForSubId(int);
-    method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+    method public static android.net.Uri getUriForSubscriptionId(int);
+    method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
     field public static final java.lang.String AUTHORITY = "service-state";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -33926,6 +33865,8 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    field public static final java.lang.String ARCHIVED = "archived";
+    field public static final java.lang.String BACKED_UP = "backed_up";
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -33933,6 +33874,7 @@
     field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String HAS_CONTENT = "has_content";
+    field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
     field public static final java.lang.String IS_READ = "is_read";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
     field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -33940,6 +33882,7 @@
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final java.lang.String RESTORED = "restored";
     field public static final java.lang.String SOURCE_DATA = "source_data";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
     field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -37201,7 +37144,6 @@
   }
 
   public static final class Connection.RttModifyStatus {
-    ctor public Connection.RttModifyStatus();
     field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
     field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
     field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
@@ -37691,7 +37633,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
@@ -37775,9 +37718,13 @@
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -38277,7 +38224,6 @@
     method public android.os.PersistableBundle getCarrierConfig();
     method public deprecated android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
-    method public boolean getDataEnabled();
     method public int getDataNetworkType();
     method public int getDataState();
     method public deprecated java.lang.String getDeviceId();
@@ -38309,6 +38255,7 @@
     method public int getSimState();
     method public int getSimState(int);
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getVisualVoicemailPackageName();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public int getVoiceNetworkType();
@@ -38321,6 +38268,8 @@
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public boolean isConcurrentVoiceAndDataAllowed();
+    method public boolean isDataEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
@@ -38330,6 +38279,7 @@
     method public boolean isWorldPhone();
     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 setDataEnabled(boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
@@ -38404,6 +38354,57 @@
     field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
   }
 
+  public static abstract class TelephonyManager.OnReceiveUssdResponseCallback {
+    ctor public TelephonyManager.OnReceiveUssdResponseCallback();
+    method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence);
+    method public void onReceiveUssdResponseFailed(java.lang.String, int);
+  }
+
+  public abstract class VisualVoicemailService extends android.app.Service {
+    ctor public VisualVoicemailService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+    method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+    method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+    method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+  }
+
+  public static class VisualVoicemailService.VisualVoicemailTask {
+    method public final void finish();
+  }
+
+  public final class VisualVoicemailSms implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getFields();
+    method public java.lang.String getMessageBody();
+    method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method public java.lang.String getPrefix();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
+  }
+
+  public final class VisualVoicemailSmsFilterSettings implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
+    field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
+    field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
+    field public final java.lang.String clientPrefix;
+    field public final int destinationPort;
+    field public final java.util.List<java.lang.String> originatingNumbers;
+  }
+
+  public static class VisualVoicemailSmsFilterSettings.Builder {
+    ctor public VisualVoicemailSmsFilterSettings.Builder();
+    method public android.telephony.VisualVoicemailSmsFilterSettings build();
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
+  }
+
 }
 
 package android.telephony.cdma {
@@ -49817,15 +49818,15 @@
     ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
   }
 
-  public final class DexFile {
-    ctor public DexFile(java.io.File) throws java.io.IOException;
-    ctor public DexFile(java.lang.String) throws java.io.IOException;
+  public final deprecated class DexFile {
+    ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
+    ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<java.lang.String> entries();
     method public java.lang.String getName();
     method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
     method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
-    method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+    method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
   public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 845a47d..ff52f27 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -466,6 +466,30 @@
         "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
 
     /**
+     * Intent used to broadcast the change in the Bluetooth address
+     * of the local Bluetooth adapter.
+     * <p>Always contains the extra field {@link
+     * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address.
+     *
+     * Note: only system level processes are allowed to send this
+     * defined broadcast.
+     *
+     * @hide
+     */
+    public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
+        "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
+
+    /**
+     * Used as a String extra field in {@link
+     * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local
+     * Bluetooth address.
+     *
+     * @hide
+     */
+    public static final String EXTRA_BLUETOOTH_ADDRESS =
+          "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS";
+
+    /**
      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
      * by BLE Always on enabled application to know the ACL_CONNECTED event
      * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
@@ -1008,28 +1032,6 @@
     }
 
     /**
-     * enable or disable Bluetooth HCI snoop log.
-     *
-     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission
-     *
-     * @return true to indicate configure HCI log successfully, or false on
-     *         immediate error
-     * @hide
-     */
-    public boolean configHciSnoopLog(boolean enable) {
-        try {
-            mServiceLock.readLock().lock();
-            if (mService != null) return mService.configHciSnoopLog(enable);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        } finally {
-            mServiceLock.readLock().unlock();
-        }
-        return false;
-    }
-
-    /**
      * Factory reset bluetooth settings.
      *
      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}
@@ -1484,8 +1486,8 @@
     }
 
     /**
-     * Return the maximum LE advertising data length,
-     * if LE Extended Advertising feature is supported.
+     * Return the maximum LE advertising data length in bytes,
+     * if LE Extended Advertising feature is supported, 0 otherwise.
      *
      * @return the maximum LE advertising data length.
      */
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 1a969b9..40f10a8 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,16 @@
                 }
                 mClientIf = clientIf;
                 if (status != GATT_SUCCESS) {
-                    mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
-                                                      BluetoothProfile.STATE_DISCONNECTED);
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (mCallback != null) {
+                                mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
+                                                  BluetoothProfile.STATE_DISCONNECTED);
+                            }
+                        }
+                    });
+
                     synchronized(mStateLock) {
                         mConnState = CONN_STATE_IDLE;
                     }
@@ -181,11 +191,14 @@
                     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() {
+                        if (mCallback != null) {
+                            mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -200,11 +213,14 @@
                     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() {
+                        if (mCallback != null) {
+                            mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -221,11 +237,16 @@
                 }
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onConnectionStateChange(BluetoothGatt.this, status,
+                                                              profileState);
+                        }
+                    }
+                });
 
                 synchronized(mStateLock) {
                     if (connected) {
@@ -279,11 +300,14 @@
                     }
                 }
 
-                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() {
+                        if (mCallback != null) {
+                            mCallback.onServicesDiscovered(BluetoothGatt.this, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -328,11 +352,15 @@
 
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic,
+                                                           status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -373,11 +401,15 @@
 
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic,
+                                                            status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -398,11 +430,14 @@
 
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
+                        }
+                    }
+                });
             }
 
             /**
@@ -442,11 +477,14 @@
 
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -485,11 +523,14 @@
 
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -508,11 +549,14 @@
                     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() {
+                        if (mCallback != null) {
+                           mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -526,11 +570,14 @@
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -544,11 +591,15 @@
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
+                        }
+                    }
+                });
             }
 
             /**
@@ -564,12 +615,16 @@
                 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() {
+                        if (mCallback != null) {
+                            mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
+                                                          timeout, status);
+                        }
+                    }
+                });
             }
         };
 
@@ -659,11 +714,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 +772,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 +784,7 @@
 
         mAutoConnect = autoConnect;
 
-        if (!registerApp(callback)) {
+        if (!registerApp(callback, handler)) {
             synchronized(mStateLock) {
                 mConnState = CONN_STATE_IDLE;
             }
@@ -947,6 +1004,41 @@
     }
 
     /**
+     * Reads the characteristic using its UUID from the associated remote device.
+     *
+     * <p>This is an asynchronous operation. The result of the read operation
+     * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
+     * callback.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param uuid UUID of characteristic to read from the remote device
+     * @return true, if the read operation was initiated successfully
+     * @hide
+     */
+    public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
+        if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
+        if (mService == null || mClientIf == 0) return false;
+
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
+        try {
+            mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
+                new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            mDeviceBusy = false;
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /**
      * Writes a given characteristic and its values to the associated remote device.
      *
      * <p>Once the write operation has been completed, the
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/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index b337817..43c5ae4 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -97,7 +97,6 @@
     ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in ParcelUuid uuid, int port, int flag);
     ParcelFileDescriptor createSocketChannel(int type, in String serviceName, in ParcelUuid uuid, int port, int flag);
 
-    boolean configHciSnoopLog(boolean enable);
     boolean factoryReset();
 
     boolean isMultiAdvertisementSupported();
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 334e88b..fb6b893 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -31,7 +31,6 @@
 
 import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothGattServerCallback;
-import android.bluetooth.le.IAdvertiserCallback;
 import android.bluetooth.le.IAdvertisingSetCallback;
 import android.bluetooth.le.IPeriodicAdvertisingCallback;
 import android.bluetooth.le.IScannerCallback;
@@ -56,6 +55,7 @@
                                 in IAdvertisingSetCallback callback);
     void stopAdvertisingSet(in IAdvertisingSetCallback callback);
 
+    void getOwnAddress(in int advertiserId);
     void enableAdvertisingSet(in int advertiserId, in boolean enable, in int duration, in int maxExtAdvEvents);
     void setAdvertisingData(in int advertiserId, in AdvertiseData data);
     void setScanResponseData(in int advertiserId, in AdvertiseData data);
@@ -77,6 +77,8 @@
     void refreshDevice(in int clientIf, in String address);
     void discoverServices(in int clientIf, in String address);
     void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
+    void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid,
+                           in int startHandle, in int endHandle, in int authReq);
     void writeCharacteristic(in int clientIf, in String address, in int handle,
                             in int writeType, in int authReq, in byte[] value);
     void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 51571b2..1bc211c 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -172,7 +172,7 @@
      *
      * @param enable whether the periodic advertising should be enabled (true), or disabled (false).
      */
-    public void setPeriodicAdvertisingEnable(boolean enable) {
+    public void setPeriodicAdvertisingEnabled(boolean enable) {
         try {
             gatt.setPeriodicAdvertisingEnable(this.advertiserId, enable);
         } catch (RemoteException e) {
@@ -181,7 +181,23 @@
     }
 
     /**
-     * Returns advertiserId associated with thsi advertising set.
+     * Returns address associated with this advertising set.
+     * This method is exposed only for Bluetooth PTS tests, no app or system service
+     * should ever use it.
+     *
+     * This method requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
+     * @hide
+     */
+    public void getOwnAddress(){
+        try {
+            gatt.getOwnAddress(this.advertiserId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "remote exception - ", e);
+        }
+    }
+
+    /**
+     * Returns advertiserId associated with this advertising set.
      *
      * @hide
      */
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
index fe3b1cd..c3c16a4 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
@@ -135,7 +135,7 @@
                                              int status) {}
 
     /**
-     * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnable}
+     * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled}
      * indicating result of the operation.
      *
      * @param advertisingSet The advertising set.
@@ -143,4 +143,15 @@
      */
     public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
                                             int status) {}
+
+    /**
+     * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()}
+     * indicating result of the operation.
+     *
+     * @param advertisingSet The advertising set.
+     * @param addressType type of address.
+     * @param address advertising set bluetooth address.
+     * @hide
+     */
+    public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {}
 }
\ No newline at end of file
diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
index 31d8f48..71c4484 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
@@ -242,7 +242,7 @@
          * non-connectable.
          * Legacy advertisements can be both connectable and scannable. Non-legacy
          * advertisements can be only scannable or only connectable.
-         * @param connectable Controls whether the advertisment type will be
+         * @param connectable Controls whether the advertisement type will be
          * connectable (true) or non-connectable (false).
          */
         public Builder setConnectable(boolean connectable) {
@@ -254,7 +254,7 @@
          * Set whether the advertisement type should be scannable.
          * Legacy advertisements can be both connectable and scannable. Non-legacy
          * advertisements can be only scannable or only connectable.
-         * @param scannable Controls whether the advertisment type will be
+         * @param scannable Controls whether the advertisement type will be
          * scannable (true) or non-scannable (false).
          */
         public Builder setScannable(boolean scannable) {
@@ -386,6 +386,7 @@
 
         /**
          * Build the {@link AdvertisingSetParameters} object.
+         * @throws IllegalStateException if invalid combination of parameters is used.
          */
         public AdvertisingSetParameters build() {
             if (isLegacy) {
@@ -394,22 +395,22 @@
                 }
 
                 if (connectable == true && scannable == false) {
-                    throw new IllegalArgumentException(
+                    throw new IllegalStateException(
                         "Legacy advertisement can't be connectable and non-scannable");
                 }
 
                 if (includeTxPower) {
-                    throw new IllegalArgumentException(
+                    throw new IllegalStateException(
                         "Legacy advertising can't include TX power level in header");
                 }
             } else {
                 if (connectable && scannable) {
-                    throw new IllegalArgumentException(
+                    throw new IllegalStateException(
                         "Advertising can't be both connectable and scannable");
                 }
 
                 if (isAnonymous && connectable) {
-                    throw new IllegalArgumentException(
+                    throw new IllegalStateException(
                         "Advertising can't be both connectable and anonymous");
                 }
             }
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index ea3031b..67d56d5 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -22,7 +22,6 @@
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothManager;
-import android.bluetooth.le.IAdvertiserCallback;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelUuid;
@@ -545,6 +544,17 @@
             }
 
             @Override
+            public void onOwnAddressRead(int advertiserId, int addressType, String address) {
+                handler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
+                        callback.onOwnAddressRead(advertisingSet, addressType, address);
+                    }
+                });
+            }
+
+            @Override
             public void onAdvertisingSetStopped(int advertiserId) {
                 handler.post(new Runnable() {
                     @Override
diff --git a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
index 2c9f4ba..3628c77 100644
--- a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
+++ b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
@@ -21,6 +21,7 @@
  */
 oneway interface IAdvertisingSetCallback {
   void onAdvertisingSetStarted(in int advertiserId, in int tx_power, in int status);
+  void onOwnAddressRead(in int advertiserId, in int addressType, in String address);
   void onAdvertisingSetStopped(in int advertiserId);
   void onAdvertisingEnabled(in int advertiserId, in boolean enable, in int status);
   void onAdvertisingDataSet(in int advertiserId, in int status);
diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java
index 5b2fa40..e552398 100644
--- a/core/java/android/bluetooth/le/ScanResult.java
+++ b/core/java/android/bluetooth/le/ScanResult.java
@@ -52,6 +52,16 @@
     public static final int SID_NOT_PRESENT = 0xFF;
 
     /**
+     * TX power is not present in the packet.
+     */
+    public static final int TX_POWER_NOT_PRESENT = 0x7F;
+
+    /**
+     * Periodic advertising interval is not present in the packet.
+     */
+    public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0x00;
+
+    /**
      * Mask for checking whether event type represents legacy advertisement.
      */
     private static final int ET_LEGACY_MASK = 0x10;
@@ -265,15 +275,16 @@
 
     /**
      * Returns the transmit power in dBm.
-     * Valid range is [-127, 126]. A value of 127 indicates that the
-     * advertisement did not indicate TX power.
+     * Valid range is [-127, 126]. A value of {@link ScanResult#TX_POWER_NOT_PRESENT}
+     * indicates that the TX power is not present.
      */
     public int getTxPower() { return mTxPower; }
 
     /**
      * Returns the periodic advertising interval in units of 1.25ms.
-     * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of 0 means
-     * periodic advertising is not used for this scan result.
+     * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of
+     * {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means periodic
+     * advertising interval is not present.
      */
     public int getPeriodicAdvertisingInterval() {
         return mPeriodicAdvertisingInterval;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2512854..b2f2cb7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2762,9 +2762,6 @@
      *  <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
      *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
      *  handling management of network connections.
-     *  <dt> {@link #IPSEC_SERVICE} ("ipsec")
-     *  <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
-     *  sockets and networks.
      *  <dt> {@link #WIFI_SERVICE} ("wifi")
      *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
      *  connectivity.  On releases before NYC, it should only be obtained from an application
@@ -3099,6 +3096,7 @@
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
+     * @hide
      * @see #getSystemService
      */
     public static final String IPSEC_SERVICE = "ipsec";
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 14bb923..f079647 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -755,8 +755,9 @@
             if (!(obj instanceof BandConfig))
                 return false;
             BandConfig other = (BandConfig) obj;
-            if (mDescriptor != other.getDescriptor())
-                return false;
+            BandDescriptor otherDesc = other.getDescriptor();
+            if ((mDescriptor == null) != (otherDesc == null)) return false;
+            if (mDescriptor != null && !mDescriptor.equals(otherDesc)) return false;
             return true;
         }
     }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0e5d049..efa1959 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -48,7 +48,6 @@
 
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.util.MessageUtils;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
@@ -302,7 +301,8 @@
     /**
      * Broadcast Action: A tetherable connection has come or gone.
      * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER},
-     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and
+     * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY},
+     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and
      * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate
      * the current state of tethering.  Each include a list of
      * interface names in that state (may be empty).
@@ -321,10 +321,17 @@
 
     /**
      * @hide
-     * gives a String[] listing all the interfaces currently tethered
-     * (ie, has dhcp support and packets potentially forwarded/NATed)
+     * gives a String[] listing all the interfaces currently in local-only
+     * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
      */
-    public static final String EXTRA_ACTIVE_TETHER = "activeArray";
+    public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+
+    /**
+     * @hide
+     * gives a String[] listing all the interfaces currently tethered
+     * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
+     */
+    public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
 
     /**
      * @hide
@@ -1863,8 +1870,12 @@
                 .getPackageNameForUid(context, uid), true /* throwException */);
     }
 
-    /** {@hide */
-    public static final void enforceTetherChangePermission(Context context) {
+    /** {@hide} */
+    public static final void enforceTetherChangePermission(Context context, String callingPkg) {
+        if (null == context || null == callingPkg) {
+            throw new IllegalArgumentException("arguments should not be null");
+        }
+
         if (context.getResources().getStringArray(
                 com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {
             // Have a provisioning app - must only let system apps (which check this app)
@@ -1873,8 +1884,10 @@
                     android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService");
         } else {
             int uid = Binder.getCallingUid();
-            Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings
-                    .getPackageNameForUid(context, uid), true /* throwException */);
+            // If callingPkg's uid is not same as Binder.getCallingUid(),
+            // AppOpsService throws SecurityException.
+            Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPkg,
+                    true /* throwException */);
         }
     }
 
@@ -1997,7 +2010,9 @@
      */
     public int tether(String iface) {
         try {
-            return mService.tether(iface);
+            String pkgName = mContext.getOpPackageName();
+            Log.i(TAG, "tether caller:" + pkgName);
+            return mService.tether(iface, pkgName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2023,7 +2038,9 @@
      */
     public int untether(String iface) {
         try {
-            return mService.untether(iface);
+            String pkgName = mContext.getOpPackageName();
+            Log.i(TAG, "untether caller:" + pkgName);
+            return mService.untether(iface, pkgName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2114,7 +2131,9 @@
         };
 
         try {
-            mService.startTethering(type, wrappedCallback, showProvisioningUi);
+            String pkgName = mContext.getOpPackageName();
+            Log.i(TAG, "startTethering caller:" + pkgName);
+            mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
         } catch (RemoteException e) {
             Log.e(TAG, "Exception trying to start tethering.", e);
             wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
@@ -2134,7 +2153,9 @@
     @SystemApi
     public void stopTethering(int type) {
         try {
-            mService.stopTethering(type);
+            String pkgName = mContext.getOpPackageName();
+            Log.i(TAG, "stopTethering caller:" + pkgName);
+            mService.stopTethering(type, pkgName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2219,7 +2240,9 @@
      */
     public int setUsbTethering(boolean enable) {
         try {
-            return mService.setUsbTethering(enable);
+            String pkgName = mContext.getOpPackageName();
+            Log.i(TAG, "setUsbTethering caller:" + pkgName);
+            return mService.setUsbTethering(enable, pkgName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2693,18 +2716,12 @@
     public static final int CALLBACK_CAP_CHANGED         = BASE + 6;
     /** @hide */
     public static final int CALLBACK_IP_CHANGED          = BASE + 7;
-    // TODO: consider deleting CALLBACK_RELEASED and shifting following enum codes down by 1.
-    /** @hide */
-    public static final int CALLBACK_RELEASED            = BASE + 8;
-    // TODO: consider deleting CALLBACK_EXIT and shifting following enum codes down by 1.
-    /** @hide */
-    public static final int CALLBACK_EXIT                = BASE + 9;
     /** @hide obj = NetworkCapabilities, arg1 = seq number */
-    private static final int EXPIRE_LEGACY_REQUEST       = BASE + 10;
+    private static final int EXPIRE_LEGACY_REQUEST       = BASE + 8;
     /** @hide */
-    public static final int CALLBACK_SUSPENDED           = BASE + 11;
+    public static final int CALLBACK_SUSPENDED           = BASE + 9;
     /** @hide */
-    public static final int CALLBACK_RESUMED             = BASE + 12;
+    public static final int CALLBACK_RESUMED             = BASE + 10;
 
     /** @hide */
     public static String getCallbackName(int whichCallback) {
@@ -2716,8 +2733,6 @@
             case CALLBACK_UNAVAIL:      return "CALLBACK_UNAVAIL";
             case CALLBACK_CAP_CHANGED:  return "CALLBACK_CAP_CHANGED";
             case CALLBACK_IP_CHANGED:   return "CALLBACK_IP_CHANGED";
-            case CALLBACK_RELEASED:     return "CALLBACK_RELEASED";
-            case CALLBACK_EXIT:         return "CALLBACK_EXIT";
             case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
             case CALLBACK_SUSPENDED:    return "CALLBACK_SUSPENDED";
             case CALLBACK_RESUMED:      return "CALLBACK_RESUMED";
@@ -2743,46 +2758,46 @@
             NetworkRequest request = getObject(message, NetworkRequest.class);
             Network network = getObject(message, Network.class);
             if (DBG) {
-                Log.d(TAG, whatToString(message.what) + " for network " + network);
+                Log.d(TAG, getCallbackName(message.what) + " for network " + network);
             }
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
-                    NetworkCallback callback = getCallback(request, "PRECHECK");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onPreCheck(network);
                     }
                     break;
                 }
                 case CALLBACK_AVAILABLE: {
-                    NetworkCallback callback = getCallback(request, "AVAILABLE");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onAvailable(network);
                     }
                     break;
                 }
                 case CALLBACK_LOSING: {
-                    NetworkCallback callback = getCallback(request, "LOSING");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onLosing(network, message.arg1);
                     }
                     break;
                 }
                 case CALLBACK_LOST: {
-                    NetworkCallback callback = getCallback(request, "LOST");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onLost(network);
                     }
                     break;
                 }
                 case CALLBACK_UNAVAIL: {
-                    NetworkCallback callback = getCallback(request, "UNAVAIL");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onUnavailable();
                     }
                     break;
                 }
                 case CALLBACK_CAP_CHANGED: {
-                    NetworkCallback callback = getCallback(request, "CAP_CHANGED");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
                         callback.onCapabilitiesChanged(network, cap);
@@ -2790,7 +2805,7 @@
                     break;
                 }
                 case CALLBACK_IP_CHANGED: {
-                    NetworkCallback callback = getCallback(request, "IP_CHANGED");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         LinkProperties lp = getObject(message, LinkProperties.class);
                         callback.onLinkPropertiesChanged(network, lp);
@@ -2798,25 +2813,19 @@
                     break;
                 }
                 case CALLBACK_SUSPENDED: {
-                    NetworkCallback callback = getCallback(request, "SUSPENDED");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onNetworkSuspended(network);
                     }
                     break;
                 }
                 case CALLBACK_RESUMED: {
-                    NetworkCallback callback = getCallback(request, "RESUMED");
+                    NetworkCallback callback = getCallback(message);
                     if (callback != null) {
                         callback.onNetworkResumed(network);
                     }
                     break;
                 }
-                case CALLBACK_RELEASED: {
-                    break;
-                }
-                case CALLBACK_EXIT: {
-                    break;
-                }
                 case EXPIRE_LEGACY_REQUEST: {
                     expireRequest((NetworkCapabilities)message.obj, message.arg1);
                     break;
@@ -2828,13 +2837,14 @@
             return (T) msg.getData().getParcelable(c.getSimpleName());
         }
 
-        private NetworkCallback getCallback(NetworkRequest req, String name) {
+        private NetworkCallback getCallback(Message msg) {
+            final NetworkRequest req = getObject(msg, NetworkRequest.class);
             final NetworkCallback callback;
             synchronized(sCallbacks) {
                 callback = sCallbacks.get(req);
             }
             if (callback == null) {
-                Log.w(TAG, "callback not found for " + name + " message");
+                Log.w(TAG, "callback not found for " + getCallbackName(msg.what) + " message");
             }
             return callback;
         }
@@ -3721,32 +3731,4 @@
             throw e.rethrowFromSystemServer();
         }
     }
-
-    /**
-     * A holder class for debug info (mapping CALLBACK values to field names). This is stored
-     * in a holder for two reasons:
-     * 1) The reflection necessary to establish the map can't be run at compile-time. Thus, this
-     *    code will make the enclosing class not compile-time initializeable, deferring its
-     *    initialization to zygote startup. This leads to dirty (but shared) memory.
-     *    As this is debug info, use a holder that isn't initialized by default. This way the map
-     *    will be created on demand, while ConnectivityManager can be compile-time initialized.
-     * 2) Static initialization is still preferred for its strong thread safety guarantees without
-     *    requiring a lock.
-     */
-    private static class NoPreloadHolder {
-        public static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
-                new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
-    }
-
-    static {
-        // When debug is enabled, aggressively initialize the holder by touching the field (which
-        // will guarantee static initialization).
-        if (CallbackHandler.DBG) {
-            Object dummy = NoPreloadHolder.sMagicDecoderRing;
-        }
-    }
-
-    private static final String whatToString(int what) {
-        return NoPreloadHolder.sMagicDecoderRing.get(what, Integer.toString(what));
-    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 425e494..63a1f051 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -69,17 +69,18 @@
 
     boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
 
-    int tether(String iface);
+    int tether(String iface, String callerPkg);
 
-    int untether(String iface);
+    int untether(String iface, String callerPkg);
 
     int getLastTetherError(String iface);
 
     boolean isTetheringSupported();
 
-    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi);
+    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi,
+            String callerPkg);
 
-    void stopTethering(int type);
+    void stopTethering(int type, String callerPkg);
 
     String[] getTetherableIfaces();
 
@@ -95,7 +96,7 @@
 
     String[] getTetherableBluetoothRegexs();
 
-    int setUsbTethering(boolean enable);
+    int setUsbTethering(boolean enable, String callerPkg);
 
     void reportInetCondition(int networkType, int percentage);
 
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index ce7894f..48b095d 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -24,6 +24,8 @@
 /**
  * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
  * RFC 4301.
+ *
+ * @hide
  */
 public final class IpSecAlgorithm implements Parcelable {
 
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index f8702e2..114e46e 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -37,6 +37,8 @@
  * <p>An IpSecManager may be obtained by calling {@link
  * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
  * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ *
+ * @hide
  */
 public final class IpSecManager {
     private static final String TAG = "IpSecManager";
@@ -245,6 +247,7 @@
      *
      * @param socket a stream socket
      * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+     * @hide
      */
     public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
             throws IOException {
@@ -262,6 +265,7 @@
      *
      * @param socket a datagram socket
      * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+     * @hide
      */
     public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
             throws IOException {
@@ -284,7 +288,7 @@
      * address associated with that transform will throw an IOException. In addition, if the
      * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
      * send() or receive() until the transform is removed from the socket by calling {@link
-     * #removeTransportModeTransform(Socket, IpSecTransform)};
+     * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
      *
      * @param socket a socket file descriptor
      * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
@@ -316,8 +320,10 @@
      *
      * @param socket a socket that previously had a transform applied to it.
      * @param transform the IPsec Transform that was previously applied to the given socket
+     * @hide
      */
-    public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
+    public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
+            throws IOException {
         removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
     }
 
@@ -330,8 +336,10 @@
      *
      * @param socket a socket that previously had a transform applied to it.
      * @param transform the IPsec Transform that was previously applied to the given socket
+     * @hide
      */
-    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
+    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
+            throws IOException {
         removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
     }
 
@@ -345,7 +353,8 @@
      * @param socket a socket file descriptor that previously had a transform applied to it.
      * @param transform the IPsec Transform that was previously applied to the given socket
      */
-    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) {
+    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
+            throws IOException {
         removeTransportModeTransform(new ParcelFileDescriptor(socket), transform);
     }
 
@@ -419,7 +428,7 @@
          *
          * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
          */
-        public void close() {
+        public void close() throws IOException {
             // TODO: Go close the socket
             mCloseGuard.close();
         }
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 801e98c..639d1f2 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -45,6 +45,8 @@
  *
  * <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
  * of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ *
+ * @hide
  */
 public final class IpSecTransform implements AutoCloseable {
     private static final String TAG = "IpSecTransform";
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index c28294f..1da0d28 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -18,7 +18,9 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.BitUtils;
 
 import java.util.Objects;
 
@@ -229,7 +231,8 @@
      * Capabilities that suggest that a network is restricted.
      * {@see #maybeMarkCapabilitiesRestricted}.
      */
-    private static final long RESTRICTED_CAPABILITIES =
+    @VisibleForTesting
+    /* package */ static final long RESTRICTED_CAPABILITIES =
             (1 << NET_CAPABILITY_CBS) |
             (1 << NET_CAPABILITY_DUN) |
             (1 << NET_CAPABILITY_EIMS) |
@@ -240,6 +243,17 @@
             (1 << NET_CAPABILITY_XCAP);
 
     /**
+     * Capabilities that suggest that a network is unrestricted.
+     * {@see #maybeMarkCapabilitiesRestricted}.
+     */
+    @VisibleForTesting
+    /* package */ static final long UNRESTRICTED_CAPABILITIES =
+            (1 << NET_CAPABILITY_INTERNET) |
+            (1 << NET_CAPABILITY_MMS) |
+            (1 << NET_CAPABILITY_SUPL) |
+            (1 << NET_CAPABILITY_WIFI_P2P);
+
+    /**
      * Adds the given capability to this {@code NetworkCapability} instance.
      * Multiple capabilities may be applied sequentially.  Note that when searching
      * for a network to satisfy a request, all capabilities requested must be satisfied.
@@ -279,7 +293,7 @@
      * @hide
      */
     public int[] getCapabilities() {
-        return enumerateBits(mNetworkCapabilities);
+        return BitUtils.unpackBits(mNetworkCapabilities);
     }
 
     /**
@@ -295,19 +309,6 @@
         return ((mNetworkCapabilities & (1 << capability)) != 0);
     }
 
-    private int[] enumerateBits(long val) {
-        int size = Long.bitCount(val);
-        int[] result = new int[size];
-        int index = 0;
-        int resource = 0;
-        while (val > 0) {
-            if ((val & 1) == 1) result[index++] = resource;
-            val = val >> 1;
-            resource++;
-        }
-        return result;
-    }
-
     private void combineNetCapabilities(NetworkCapabilities nc) {
         this.mNetworkCapabilities |= nc.mNetworkCapabilities;
     }
@@ -365,12 +366,16 @@
      * @hide
      */
     public void maybeMarkCapabilitiesRestricted() {
-        // If all the capabilities are typically provided by restricted networks, conclude that this
-        // network is restricted.
-        if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0 &&
-                // Must have at least some restricted capabilities, otherwise a request for an
-                // internet-less network will get marked restricted.
-                (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0) {
+        // Verify there aren't any unrestricted capabilities.  If there are we say
+        // the whole thing is unrestricted.
+        final boolean hasUnrestrictedCapabilities =
+                ((mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0);
+
+        // Must have at least some restricted capabilities.
+        final boolean hasRestrictedCapabilities =
+                ((mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0);
+
+        if (hasRestrictedCapabilities && !hasUnrestrictedCapabilities) {
             removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
         }
     }
@@ -416,6 +421,15 @@
     private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
     private static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;
 
+    private static final String[] TRANSPORT_NAMES = {
+        "CELLULAR",
+        "WIFI",
+        "BLUETOOTH",
+        "ETHERNET",
+        "VPN",
+        "WIFI_AWARE"
+    };
+
     /**
      * Adds the given transport type to this {@code NetworkCapability} instance.
      * Multiple transports may be applied sequentially.  Note that when searching
@@ -462,7 +476,7 @@
      * @hide
      */
     public int[] getTransportTypes() {
-        return enumerateBits(mTransportTypes);
+        return BitUtils.unpackBits(mTransportTypes);
     }
 
     /**
@@ -869,18 +883,23 @@
      * @hide
      */
     public static String transportNamesOf(int[] types) {
-        String transports = "";
-        for (int i = 0; i < types.length;) {
-            switch (types[i]) {
-                case TRANSPORT_CELLULAR:    transports += "CELLULAR"; break;
-                case TRANSPORT_WIFI:        transports += "WIFI"; break;
-                case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
-                case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
-                case TRANSPORT_VPN:         transports += "VPN"; break;
-                case TRANSPORT_WIFI_AWARE:  transports += "WIFI_AWARE"; break;
-            }
-            if (++i < types.length) transports += "|";
+        if (types == null || types.length == 0) {
+            return "";
         }
-        return transports;
+        StringBuilder transports = new StringBuilder();
+        for (int t : types) {
+            transports.append("|").append(transportNameOf(t));
+        }
+        return transports.substring(1);
+    }
+
+    /**
+     * @hide
+     */
+    public static String transportNameOf(int transport) {
+        if (transport < 0 || TRANSPORT_NAMES.length <= transport) {
+            return "UNKNOWN";
+        }
+        return TRANSPORT_NAMES[transport];
     }
 }
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/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 1dde3ca..3fd9f19 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -31,6 +31,7 @@
 
 import java.util.concurrent.CountDownLatch;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
@@ -326,7 +327,8 @@
         public void onServiceResolved(NsdServiceInfo serviceInfo);
     }
 
-    private class ServiceHandler extends Handler {
+    @VisibleForTesting
+    class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
         }
@@ -370,6 +372,8 @@
                     ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
                     break;
                 case STOP_DISCOVERY_FAILED:
+                    // TODO: failure to stop discovery should be internal and retried internally, as
+                    // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED
                     removeListener(message.arg2);
                     ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
                             message.arg1);
@@ -391,6 +395,8 @@
                     ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
                     break;
                 case UNREGISTER_SERVICE_SUCCEEDED:
+                    // TODO: do not unregister listener until service is unregistered, or provide
+                    // alternative way for unregistering ?
                     removeListener(message.arg2);
                     ((RegistrationListener) listener).onServiceUnregistered(ns);
                     break;
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 94fd5b0..4ba1144 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -209,10 +209,11 @@
     public native final IHwBinder readStrongBinder();
 
     // Handle is stored as part of the blob.
-    public native final HwBlob readBuffer();
+    public native final HwBlob readBuffer(long expectedSize);
 
     public native final HwBlob readEmbeddedBuffer(
-            long parentHandle, long offset, boolean nullable);
+            long expectedSize, long parentHandle, long offset,
+            boolean nullable);
 
     public native final void writeBuffer(HwBlob blob);
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index dbe2f6d..c34de15 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -315,8 +315,6 @@
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
-    void setFirewallEgressSourceRule(String addr, boolean allow);
-    void setFirewallEgressDestRule(String addr, int port, boolean allow);
     void setFirewallUidRule(int chain, int uid, int rule);
     void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
     void setFirewallChainEnabled(int chain, boolean enable);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 4f4152c..2a8ae93 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -728,9 +728,11 @@
             int timeTotal = -1;
             int uncryptTime = -1;
             int sourceVersion = -1;
-            int temperature_start = -1;
-            int temperature_end = -1;
-            int temperature_max = -1;
+            int temperatureStart = -1;
+            int temperatureEnd = -1;
+            int temperatureMax = -1;
+            int errorCode = -1;
+            int causeCode = -1;
 
             while ((line = in.readLine()) != null) {
                 // Here is an example of lines in last_install:
@@ -777,11 +779,15 @@
                     bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
                             bytesStashedInMiB + scaled;
                 } else if (line.startsWith("temperature_start")) {
-                    temperature_start = scaled;
+                    temperatureStart = scaled;
                 } else if (line.startsWith("temperature_end")) {
-                    temperature_end = scaled;
+                    temperatureEnd = scaled;
                 } else if (line.startsWith("temperature_max")) {
-                    temperature_max = scaled;
+                    temperatureMax = scaled;
+                } else if (line.startsWith("error")) {
+                    errorCode = scaled;
+                } else if (line.startsWith("cause")) {
+                    causeCode = scaled;
                 }
             }
 
@@ -801,14 +807,20 @@
             if (bytesStashedInMiB != -1) {
                 MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
             }
-            if (temperature_start != -1) {
-                MetricsLogger.histogram(context, "ota_temperature_start", temperature_start);
+            if (temperatureStart != -1) {
+                MetricsLogger.histogram(context, "ota_temperature_start", temperatureStart);
             }
-            if (temperature_end != -1) {
-                MetricsLogger.histogram(context, "ota_temperature_end", temperature_end);
+            if (temperatureEnd != -1) {
+                MetricsLogger.histogram(context, "ota_temperature_end", temperatureEnd);
             }
-            if (temperature_max != -1) {
-                MetricsLogger.histogram(context, "ota_temperature_max", temperature_max);
+            if (temperatureMax != -1) {
+                MetricsLogger.histogram(context, "ota_temperature_max", temperatureMax);
+            }
+            if (errorCode != -1) {
+                MetricsLogger.histogram(context, "ota_non_ab_error_code", errorCode);
+            }
+            if (causeCode != -1) {
+                MetricsLogger.histogram(context, "ota_non_ab_cause_code", causeCode);
             }
 
         } catch (IOException e) {
diff --git a/core/java/android/os/VintfRuntimeInfo.java b/core/java/android/os/VintfRuntimeInfo.java
new file mode 100644
index 0000000..29698b9
--- /dev/null
+++ b/core/java/android/os/VintfRuntimeInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Java API for ::android::vintf::RuntimeInfo. Methods return null / 0 on any error.
+ *
+ * @hide
+ */
+public class VintfRuntimeInfo {
+
+    private VintfRuntimeInfo() {}
+
+    /**
+     * @return /sys/fs/selinux/policyvers, via security_policyvers() native call
+     */
+    public static native long getKernelSepolicyVersion();
+    /**
+     * @return content of /proc/cpuinfo
+     */
+    public static native String getCpuInfo();
+    /**
+     * @return os name extracted from uname() native call
+     */
+    public static native String getOsName();
+    /**
+     * @return node name extracted from uname() native call
+     */
+    public static native String getNodeName();
+    /**
+     * @return os release extracted from uname() native call
+     */
+    public static native String getOsRelease();
+    /**
+     * @return os version extracted from uname() native call
+     */
+    public static native String getOsVersion();
+    /**
+     * @return hardware id extracted from uname() native call
+     */
+    public static native String getHardwareId();
+    /**
+     * @return kernel version extracted from uname() native call. Format is
+     * {@code x.y.z}.
+     */
+    public static native String getKernelVersion();
+    /**
+     * @return libavb version in OS. Format is {@code x.y}.
+     */
+    public static native String getBootAvbVersion();
+    /**
+     * @return libavb version in bootloader. Format is {@code x.y}.
+     */
+    public static native String getBootVbmetaAvbVersion();
+
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3f3f859..35a3c0c 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4720,13 +4720,6 @@
         public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
 
         /**
-         * bluetooth HCI snoop log configuration
-         * @hide
-         */
-        public static final String BLUETOOTH_HCI_LOG =
-                "bluetooth_hci_log";
-
-        /**
          * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
          */
         @Deprecated
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 1e54163..a8b094e 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -107,15 +107,7 @@
 
     /**
      * Broadcast intent to inform a new visual voicemail SMS has been received. This intent will
-     * only be delivered to the voicemail client. The intent will have the following extra values:
-     *
-     * <ul>
-     *   <li><em>{@link #EXTRA_VOICEMAIL_SMS_TYPE}</em> - (String) The event type of the SMS. Common
-     *   values are "SYNC" or "STATUS"</li>
-     *   <li><em>{@link #EXTRA_VOICEMAIL_SMS_DATA}</em> - (Bundle) The fields sent by the SMS</li>
-     *   <li><em>{@link #EXTRA_VOICEMAIL_SMS_SUBID}</em> - (Integer) The subscription ID of the
-     *   phone account that received the SMS</li>
-     * </ul>
+     * only be delivered to the telephony service. {@link #EXTRA_VOICEMAIL_SMS} will be included.
      */
     /** @hide */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -123,42 +115,11 @@
             "android.intent.action.VOICEMAIL_SMS_RECEIVED";
 
     /**
-     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
-     * indicate the event type of the SMS. Common values are "SYNC" or "STATUS". The extra will not
-     * exist if the framework cannot parse the SMS as voicemail but the carrier pattern indicates
-     * it is.
-     */
-    /** @hide */
-    public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
-            "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
-
-    /**
-     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
-     * indicate the fields sent by the SMS. The extra will not exist if the framework cannot
-     * parse the SMS as voicemail but the carrier pattern indicates it is.
-     */
-    /** @hide */
-    public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
-            "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
-
-    /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * message body of the SMS. This extra is included if the framework cannot
-     * parse the SMS as voicemail but the carrier pattern indicates it is.
-     */
-    /**
+     * Extra in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} indicating the content of the SMS.
+     *
      * @hide
      */
-    public static final String EXTRA_VOICEMAIL_SMS_MESSAGE_BODY =
-        "com.android.voicemail.extra.VOICEMAIL_SMS_MESSAGE_BODY";
-
-    /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
-     * subscription ID of the phone account that received the SMS.
-     */
-    /** @hide */
-    public static final String EXTRA_VOICEMAIL_SMS_SUBID =
-            "com.android.voicemail.extra.VOICEMAIL_SMS_SUBID";
+    public static final String EXTRA_VOICEMAIL_SMS = "android.provider.extra.VOICEMAIL_SMS";
 
     /**
      * Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
@@ -323,8 +284,6 @@
          * not.
          *
          * <P>Type: INTEGER (boolean)</P>
-         *
-         * @hide
          */
         public static final String BACKED_UP = "backed_up";
 
@@ -333,8 +292,6 @@
          * restored, 0 if not.
          *
          * <P>Type: INTEGER (boolean)</P>
-         *
-         * @hide
          */
         public static final String RESTORED = "restored";
 
@@ -344,19 +301,19 @@
          * if not.
          *
          * <P>Type: INTEGER (boolean)</P>
-         *
-         * @hide
          */
         public static final String ARCHIVED = "archived";
 
         /**
          * Flag to indicate the voicemail is a OMTP voicemail handled by the {@link
          * android.telephony.VisualVoicemailService}. The UI should only show OMTP voicemails from
-         * the current visual voicemail package.
+         * the current visual voicemail package. For example, the selection could be
+         * {@code WHERE (IS_OMTP_VOICEMAIL == 0) OR ( IS_OMTP_VOICEMAIL == 1 AND SOURCE_PACKAGE ==
+         * "current.vvm.package")}
          *
          * <P>Type: INTEGER (boolean)</P>
          *
-         * @hide
+         * @see android.telephony.TelephonyManager#getVisualVoicemailPackageName
          */
         public static final String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
 
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index d857bf7..951aa8d 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -89,8 +89,9 @@
 
     /**
      * Exception class used to capture a stack trace in {@link #wtf}.
+     * @hide
      */
-    private static class TerribleFailure extends Exception {
+    public static class TerribleFailure extends Exception {
         TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
     }
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2e9cbf2..eef1cf5 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1920,7 +1920,7 @@
                 Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
                         mPendingEvents.size());
 
-                Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p);
+                Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p);
                 msg.setAsynchronous(true);
                 mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
                 return DISPATCH_IN_PROGRESS;
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
new file mode 100644
index 0000000..1b354d0
--- /dev/null
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.util;
+
+import android.annotation.Nullable;
+
+import libcore.util.Objects;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.UUID;
+
+/**
+ * A utility class for handling unsigned integers and unsigned arithmetics, as well as syntactic
+ * sugar methods for ByteBuffer. Useful for networking and packet manipulations.
+ * {@hide}
+ */
+public final class BitUtils {
+    private BitUtils() {}
+
+    public static boolean maskedEquals(long a, long b, long mask) {
+        return (a & mask) == (b & mask);
+    }
+
+    public static boolean maskedEquals(byte a, byte b, byte mask) {
+        return (a & mask) == (b & mask);
+    }
+
+    public static boolean maskedEquals(byte[] a, byte[] b, @Nullable byte[] mask) {
+        if (a == null || b == null) return a == b;
+        Preconditions.checkArgument(a.length == b.length, "Inputs must be of same size");
+        if (mask == null) return Arrays.equals(a, b);
+        Preconditions.checkArgument(a.length == mask.length, "Mask must be of same size as inputs");
+        for (int i = 0; i < mask.length; i++) {
+            if (!maskedEquals(a[i], b[i], mask[i])) return false;
+        }
+        return true;
+    }
+
+    public static boolean maskedEquals(UUID a, UUID b, @Nullable UUID mask) {
+        if (mask == null) {
+            return Objects.equal(a, b);
+        }
+        return maskedEquals(a.getLeastSignificantBits(), b.getLeastSignificantBits(),
+                    mask.getLeastSignificantBits())
+                && maskedEquals(a.getMostSignificantBits(), b.getMostSignificantBits(),
+                    mask.getMostSignificantBits());
+    }
+
+    public static int[] unpackBits(long val) {
+        int size = Long.bitCount(val);
+        int[] result = new int[size];
+        int index = 0;
+        int bitPos = 0;
+        while (val > 0) {
+            if ((val & 1) == 1) result[index++] = bitPos;
+            val = val >> 1;
+            bitPos++;
+        }
+        return result;
+    }
+
+    public static long packBits(int[] bits) {
+        long packed = 0;
+        for (int b : bits) {
+            packed |= (1 << b);
+        }
+        return packed;
+    }
+
+    public static int uint8(byte b) {
+        return b & 0xff;
+    }
+
+    public static int uint16(short s) {
+        return s & 0xffff;
+    }
+
+    public static long uint32(int i) {
+        return i & 0xffffffffL;
+    }
+
+    public static int bytesToBEInt(byte[] bytes) {
+        return (uint8(bytes[0]) << 24)
+                + (uint8(bytes[1]) << 16)
+                + (uint8(bytes[2]) << 8)
+                + (uint8(bytes[3]));
+    }
+
+    public static int bytesToLEInt(byte[] bytes) {
+        return Integer.reverseBytes(bytesToBEInt(bytes));
+    }
+
+    public static int getUint8(ByteBuffer buffer, int position) {
+        return uint8(buffer.get(position));
+    }
+
+    public static int getUint16(ByteBuffer buffer, int position) {
+        return uint16(buffer.getShort(position));
+    }
+
+    public static long getUint32(ByteBuffer buffer, int position) {
+        return uint32(buffer.getInt(position));
+    }
+
+    public static void put(ByteBuffer buffer, int position, byte[] bytes) {
+        final int original = buffer.position();
+        buffer.position(position);
+        buffer.put(bytes);
+        buffer.position(original);
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 0834625..7e867d7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -91,6 +91,7 @@
     android_os_Trace.cpp \
     android_os_UEventObserver.cpp \
     android_os_VintfObject.cpp \
+    android_os_VintfRuntimeInfo.cpp \
     android_net_LocalSocketImpl.cpp \
     android_net_NetUtils.cpp \
     android_net_TrafficStats.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 898c27e..2b5c0d6 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -165,6 +165,7 @@
 extern int register_android_os_Parcel(JNIEnv* env);
 extern int register_android_os_SELinux(JNIEnv* env);
 extern int register_android_os_VintfObject(JNIEnv *env);
+extern int register_android_os_VintfRuntimeInfo(JNIEnv *env);
 extern int register_android_os_seccomp(JNIEnv* env);
 extern int register_android_os_SystemProperties(JNIEnv *env);
 extern int register_android_os_SystemClock(JNIEnv* env);
@@ -529,7 +530,7 @@
 /*
  * Reads a "property" into "buffer". If the property is non-empty, it
  * is treated as a dex2oat compiler option that should be
- * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
+ * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=assume-verified".
  *
  * The "compilerArg" is a prefix for the option such as "--compiler-filter=".
  *
@@ -605,6 +606,7 @@
 {
     JavaVMInitArgs initArgs;
     char propBuf[PROPERTY_VALUE_MAX];
+    char stackTraceDirBuf[sizeof("-Xstacktracedir:")-1 + PROPERTY_VALUE_MAX];
     char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
     char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
     char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
@@ -682,7 +684,12 @@
         executionMode = kEMJitCompiler;
     }
 
-    parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
+    // If dalvik.vm.stack-trace-dir is set, it enables the "new" stack trace
+    // dump scheme and a new file is created for each stack dump. If it isn't set,
+    // the old scheme is enabled.
+    if (!parseRuntimeOption("dalvik.vm.stack-trace-dir", stackTraceDirBuf, "-Xstacktracedir:")) {
+        parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
+    }
 
     strcpy(jniOptsBuf, "-Xjniopts:");
     if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
@@ -777,7 +784,7 @@
                                "-Xmx", "-Ximage-compiler-option");
     if (skip_compilation) {
         addOption("-Ximage-compiler-option");
-        addOption("--compiler-filter=verify-none");
+        addOption("--compiler-filter=assume-verified");
     } else {
         parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
                             "--compiler-filter=", "-Ximage-compiler-option");
@@ -808,7 +815,7 @@
                                "-Xmx", "-Xcompiler-option");
     if (skip_compilation) {
         addOption("-Xcompiler-option");
-        addOption("--compiler-filter=verify-none");
+        addOption("--compiler-filter=assume-verified");
 
         // We skip compilation when a minimal runtime is brought up for decryption. In that case
         // /data is temporarily backed by a tmpfs, which is usually small.
@@ -1308,6 +1315,7 @@
     REG_JNI(register_android_os_HwParcel),
     REG_JNI(register_android_os_HwRemoteBinder),
     REG_JNI(register_android_os_VintfObject),
+    REG_JNI(register_android_os_VintfRuntimeInfo),
     REG_JNI(register_android_nio_utils),
     REG_JNI(register_android_graphics_Canvas),
     REG_JNI(register_android_graphics_Graphics),
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 678041f..b21ea828 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -574,7 +574,7 @@
     size_t parentHandle;
 
     const hidl_string *s;
-    status_t err = parcel->readBuffer(&parentHandle,
+    status_t err = parcel->readBuffer(sizeof(*s), &parentHandle,
             reinterpret_cast<const void**>(&s));
 
     if (err != OK) {
@@ -583,7 +583,7 @@
     }
 
     err = ::android::hardware::readEmbeddedFromParcel(
-            const_cast<hidl_string *>(s),
+            const_cast<hidl_string &>(*s),
             *parcel, parentHandle, 0 /* parentOffset */);
 
     if (err != OK) {
@@ -602,7 +602,7 @@
     size_t parentHandle;                                                       \
                                                                                \
     const hidl_vec<Type> *vec;                                                 \
-    status_t err = parcel->readBuffer(&parentHandle,                           \
+    status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,             \
             reinterpret_cast<const void**>(&vec));                             \
                                                                                \
     if (err != OK) {                                                           \
@@ -613,7 +613,7 @@
     size_t childHandle;                                                        \
                                                                                \
     err = ::android::hardware::readEmbeddedFromParcel(                         \
-                const_cast<hidl_vec<Type> *>(vec),                             \
+                const_cast<hidl_vec<Type> &>(*vec),                            \
                 *parcel,                                                       \
                 parentHandle,                                                  \
                 0 /* parentOffset */,                                          \
@@ -645,7 +645,7 @@
     size_t parentHandle;
 
     const hidl_vec<bool> *vec;
-    status_t err = parcel->readBuffer(&parentHandle,
+    status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
             reinterpret_cast<const void**>(&vec));
 
     if (err != OK) {
@@ -656,7 +656,7 @@
     size_t childHandle;
 
     err = ::android::hardware::readEmbeddedFromParcel(
-                const_cast<hidl_vec<bool> *>(vec),
+                const_cast<hidl_vec<bool> &>(*vec),
                 *parcel,
                 parentHandle,
                 0 /* parentOffset */,
@@ -709,7 +709,7 @@
     size_t parentHandle;
 
     const string_vec *vec;
-    status_t err = parcel->readBuffer(&parentHandle,
+    status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
             reinterpret_cast<const void **>(&vec));
 
     if (err != OK) {
@@ -719,16 +719,15 @@
 
     size_t childHandle;
     err = ::android::hardware::readEmbeddedFromParcel(
-            const_cast<string_vec *>(vec),
+            const_cast<string_vec &>(*vec),
             *parcel, parentHandle, 0 /* parentOffset */, &childHandle);
 
     for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
         err = android::hardware::readEmbeddedFromParcel(
-                    const_cast<hidl_vec<hidl_string> *>(vec),
+                    const_cast<hidl_string &>((*vec)[i]),
                     *parcel,
                     childHandle,
-                    i * sizeof(hidl_string),
-                    nullptr /* childHandle */);
+                    i * sizeof(hidl_string) /* parentOffset */);
     }
 
     if (err != OK) {
@@ -810,13 +809,20 @@
     return JHwRemoteBinder::NewObject(env, binder);
 }
 
-static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz) {
+static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz,
+                                           jlong expectedSize) {
     hardware::Parcel *parcel =
         JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
     size_t handle;
     const void *ptr;
-    status_t status = parcel->readBuffer(&handle, &ptr);
+
+    if (expectedSize < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return nullptr;
+    }
+
+    status_t status = parcel->readBuffer(expectedSize, &handle, &ptr);
 
     if (status != OK) {
         jniThrowException(env, "java/util/NoSuchElementException", NULL);
@@ -827,8 +833,8 @@
 }
 
 static jobject JHwParcel_native_readEmbeddedBuffer(
-        JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset,
-        jboolean nullable) {
+        JNIEnv *env, jobject thiz, jlong expectedSize,
+        jlong parentHandle, jlong offset, jboolean nullable) {
     hardware::Parcel *parcel =
         JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
@@ -836,8 +842,13 @@
 
     const void *ptr;
     status_t status =
-        parcel->readNullableEmbeddedBuffer(&childHandle, parentHandle, offset,
-                &ptr);
+        parcel->readNullableEmbeddedBuffer(expectedSize,
+                &childHandle, parentHandle, offset, &ptr);
+
+    if (expectedSize < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return nullptr;
+    }
 
     if (status != OK) {
         jniThrowException(env, "java/util/NoSuchElementException", NULL);
@@ -952,10 +963,10 @@
 
     { "send", "()V", (void *)JHwParcel_native_send },
 
-    { "readBuffer", "()L" PACKAGE_PATH "/HwBlob;",
+    { "readBuffer", "(J)L" PACKAGE_PATH "/HwBlob;",
         (void *)JHwParcel_native_readBuffer },
 
-    { "readEmbeddedBuffer", "(JJZ)L" PACKAGE_PATH "/HwBlob;",
+    { "readEmbeddedBuffer", "(JJJZ)L" PACKAGE_PATH "/HwBlob;",
         (void *)JHwParcel_native_readEmbeddedBuffer },
 
     { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
diff --git a/core/jni/android_os_VintfRuntimeInfo.cpp b/core/jni/android_os_VintfRuntimeInfo.cpp
new file mode 100644
index 0000000..ecb6854
--- /dev/null
+++ b/core/jni/android_os_VintfRuntimeInfo.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VintfRuntimeInfo"
+//#define LOG_NDEBUG 0
+
+#include <JNIHelp.h>
+#include <vintf/VintfObject.h>
+#include <vintf/parse_string.h>
+#include <vintf/parse_xml.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using vintf::RuntimeInfo;
+using vintf::VintfObject;
+
+#define MAP_STRING_METHOD(javaMethod, cppString)                                       \
+    static jstring android_os_VintfRuntimeInfo_##javaMethod(JNIEnv* env, jclass clazz) \
+    {                                                                                  \
+        const RuntimeInfo *info = VintfObject::GetRuntimeInfo();                       \
+        if (info == nullptr) return nullptr;                                           \
+        return env->NewStringUTF((cppString).c_str());                                 \
+    }                                                                                  \
+
+MAP_STRING_METHOD(getCpuInfo, info->cpuInfo());
+MAP_STRING_METHOD(getOsName, info->osName());
+MAP_STRING_METHOD(getNodeName, info->nodeName());
+MAP_STRING_METHOD(getOsRelease, info->osRelease());
+MAP_STRING_METHOD(getOsVersion, info->osVersion());
+MAP_STRING_METHOD(getHardwareId, info->hardwareId());
+MAP_STRING_METHOD(getKernelVersion, vintf::to_string(info->kernelVersion()));
+MAP_STRING_METHOD(getBootAvbVersion, vintf::to_string(info->bootAvbVersion()));
+MAP_STRING_METHOD(getBootVbmetaAvbVersion, vintf::to_string(info->bootVbmetaAvbVersion()));
+
+
+static jlong android_os_VintfRuntimeInfo_getKernelSepolicyVersion(JNIEnv *env, jclass clazz)
+{
+    const RuntimeInfo *info = VintfObject::GetRuntimeInfo();
+    if (info == nullptr) return 0;
+    return static_cast<jlong>(info->kernelSepolicyVersion());
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gVintfRuntimeInfoMethods[] = {
+    {"getKernelSepolicyVersion", "()J", (void*)android_os_VintfRuntimeInfo_getKernelSepolicyVersion},
+    {"getCpuInfo", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getCpuInfo},
+    {"getOsName", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getOsName},
+    {"getNodeName", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getNodeName},
+    {"getOsRelease", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getOsRelease},
+    {"getOsVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getOsVersion},
+    {"getHardwareId", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getHardwareId},
+    {"getKernelVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getKernelVersion},
+    {"getBootAvbVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getBootAvbVersion},
+    {"getBootVbmetaAvbVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getBootVbmetaAvbVersion},
+};
+
+const char* const kVintfRuntimeInfoPathName = "android/os/VintfRuntimeInfo";
+
+int register_android_os_VintfRuntimeInfo(JNIEnv* env)
+{
+    return RegisterMethodsOrDie(env, kVintfRuntimeInfoPathName, gVintfRuntimeInfoMethods, NELEM(gVintfRuntimeInfoMethods));
+}
+
+};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b95258b..6000fb5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -685,11 +685,14 @@
 
     // Grant CAP_WAKE_ALARM to the Bluetooth process.
     // Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
+    // Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
+    // audio-related threads.
     // TODO: consider making such functionality an RPC to netd.
     if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
       capabilities |= (1LL << CAP_WAKE_ALARM);
       capabilities |= (1LL << CAP_NET_RAW);
       capabilities |= (1LL << CAP_NET_BIND_SERVICE);
+      capabilities |= (1LL << CAP_SYS_NICE);
     }
 
     // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f43eb84..c2f27a9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -122,6 +122,7 @@
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.UUID" />
     <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
@@ -787,16 +788,6 @@
         android:description="@string/permdesc_callPhone"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to manage its own calls, but rely on the system to route focus to the
-         currently active call.
-        <p>Protection level: dangerous
-    -->
-    <permission android:name="android.permission.MANAGE_OWN_CALLS"
-        android:permissionGroup="android.permission-group.PHONE"
-        android:label="@string/permlab_manageOwnCalls"
-        android:description="@string/permdesc_manageOwnCalls"
-        android:protectionLevel="dangerous" />
-
     <!-- Allows an application to access the IMS call service: making and
          modifying a call
         <p>Protection level: signature|privileged
@@ -874,6 +865,17 @@
         android:description="@string/permdesc_processOutgoingCalls"
         android:protectionLevel="dangerous" />
 
+    <!-- Allows a calling application which manages it own calls through the self-managed
+         {@link android.telecom.ConnectionService} APIs.  See
+         {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED for more information on the
+         self-managed ConnectionService APIs.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.permission.MANAGE_OWN_CALLS"
+                android:label="@string/permlab_manageOwnCalls"
+                android:description="@string/permdesc_manageOwnCalls"
+                android:protectionLevel="normal" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device microphone                        -->
     <!-- ====================================================================== -->
@@ -1559,6 +1561,14 @@
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by a link {@link android.telephony.VisualVoicemailService} to ensure that
+         only the system can bind to it.
+         <p>Protection level: signature|privileged
+    -->
+    <permission
+      android:name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"
+      android:protectionLevel="signature|privileged"/>
+
     <!-- Must be required by a {@link android.telecom.CallScreeningService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
index 411a3f8..37b2a50 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -72,8 +72,6 @@
             getAddress();
         } else if ("getBondedDevices".equals(command)) {
             getBondedDevices();
-        } else if ("enableBtSnoop".equals(command)) {
-            enableBtSnoop();
         } else {
             finish(null);
         }
@@ -116,12 +114,6 @@
         finish(mSuccessResult);
     }
 
-    public void enableBtSnoop() {
-        Assert.assertTrue("failed to enable snoop log",
-                getBluetoothAdapter().configHciSnoopLog(true));
-        finish(mSuccessResult);
-    }
-
     public void finish(Bundle result) {
         if (result == null) {
             result = new Bundle();
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 2132c2b..9c253c4 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -265,7 +265,6 @@
                 / kSlowFrameBucketIntervalMs;
         framebucket = std::min(framebucket,
                 static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
-        framebucket = std::max(framebucket, 0u);
         mData->slowFrameCounts[framebucket]++;
     }
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
new file mode 100644
index 0000000..84c6cf4
--- /dev/null
+++ b/libs/input/Android.bp
@@ -0,0 +1,43 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libinputservice",
+
+    srcs: [
+        "PointerController.cpp",
+        "SpriteController.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libskia",
+        "libgui",
+        "libui",
+        "libinput",
+        "libinputflinger",
+    ],
+
+    include_dirs: ["frameworks/native/services"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+
+}
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
deleted file mode 100644
index 2bbfdcc..0000000
--- a/libs/input/Android.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    PointerController.cpp \
-    SpriteController.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-    libutils \
-    libskia \
-    libgui \
-    libui \
-    libinput \
-    libinputflinger
-
-LOCAL_C_INCLUDES := \
-    frameworks/native/services
-
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-LOCAL_MODULE:= libinputservice
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/java/android/media/session/ICallback.aidl b/media/java/android/media/session/ICallback.aidl
new file mode 100644
index 0000000..bb8a3cc
--- /dev/null
+++ b/media/java/android/media/session/ICallback.aidl
@@ -0,0 +1,34 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.media.session.MediaSession;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ */
+oneway interface ICallback {
+    void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
+            in MediaSession.Token sessionToken);
+    void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
+            in ComponentName mediaButtonReceiver);
+
+    void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
+    void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
+}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index bb59e5b..575e7d7 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -18,6 +18,7 @@
 import android.content.ComponentName;
 import android.media.IRemoteVolumeController;
 import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.os.Bundle;
@@ -41,4 +42,6 @@
 
     // For PhoneWindowManager to precheck media keys
     boolean isGlobalPriorityActive();
-}
\ No newline at end of file
+
+    void setCallback(in ICallback callback);
+}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 2364a13..31e60da 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -57,6 +57,8 @@
 
     private Context mContext;
 
+    private CallbackImpl mCallback;
+
     /**
      * @hide
      */
@@ -313,6 +315,36 @@
     }
 
     /**
+     * Set a {@link Callback}.
+     *
+     * <p>System can only have a single callback, and the callback can only be set by
+     * Bluetooth service process.
+     *
+     * @param callback A {@link Callback}. {@code null} to reset.
+     * @param handler The handler on which the callback should be invoked, or {@code null}
+     *            if the callback should be invoked on the calling thread's looper.
+     * @hide
+     */
+    public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
+        synchronized (mLock) {
+            try {
+                if (callback == null) {
+                    mCallback = null;
+                    mService.setCallback(null);
+                } else {
+                    if (handler == null) {
+                        handler = new Handler();
+                    }
+                    mCallback = new CallbackImpl(callback, handler);
+                    mService.setCallback(mCallback);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to set media key callback", e);
+            }
+        }
+    }
+
+    /**
      * Listens for changes to the list of active sessions. This can be added
      * using {@link #addOnActiveSessionsChangedListener}.
      */
@@ -320,6 +352,56 @@
         public void onActiveSessionsChanged(@Nullable List<MediaController> controllers);
     }
 
+    /**
+     * Callbacks for the media session service.
+     *
+     * <p>Called when a media key event is dispatched or the addressed player is changed.
+     * The addressed player is either the media session or the media button receiver that will
+     * receive media key events.
+     * @hide
+     */
+    public static abstract class Callback {
+        /**
+         * Called when a media key event is dispatched to the media session
+         * through the media session service.
+         *
+         * @param event Dispatched media key event.
+         * @param sessionToken The media session's token.
+         */
+        public abstract void onMediaKeyEventDispatched(KeyEvent event,
+                MediaSession.Token sessionToken);
+
+        /**
+         * Called when a media key event is dispatched to the media button receiver
+         * through the media session service.
+         * <p>MediaSessionService may broadcast key events to the media button receiver
+         * when reviving playback after the media session is released.
+         *
+         * @param event Dispatched media key event.
+         * @param mediaButtonReceiver The media button receiver.
+         */
+        public abstract void onMediaKeyEventDispatched(KeyEvent event,
+                ComponentName mediaButtonReceiver);
+
+        /**
+         * Called when the addressed player is changed to a media session.
+         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
+         * {@link #setCallback} if the addressed player exists.
+         *
+         * @param sessionToken The media session's token.
+         */
+        public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken);
+
+        /**
+         * Called when the addressed player is changed to the media button receiver.
+         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
+         * {@link #setCallback} if the addressed player exists.
+         *
+         * @param mediaButtonReceiver The media button receiver.
+         */
+        public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver);
+    }
+
     private static final class SessionsChangedWrapper {
         private Context mContext;
         private OnActiveSessionsChangedListener mListener;
@@ -360,4 +442,57 @@
             mHandler = null;
         }
     }
+
+    private static final class CallbackImpl extends ICallback.Stub {
+        private final Callback mCallback;
+        private final Handler mHandler;
+
+        public CallbackImpl(@NonNull Callback callback, @NonNull Handler handler) {
+            mCallback = callback;
+            mHandler = handler;
+        }
+
+        @Override
+        public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
+                MediaSession.Token sessionToken) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onMediaKeyEventDispatched(event, sessionToken);
+                }
+            });
+        }
+
+        @Override
+        public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
+                ComponentName mediaButtonReceiver) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onMediaKeyEventDispatched(event, mediaButtonReceiver);
+                }
+            });
+        }
+
+        @Override
+        public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onAddressedPlayerChanged(sessionToken);
+                }
+            });
+        }
+
+        @Override
+        public void onAddressedPlayerChangedToMediaButtonReceiver(
+                ComponentName mediaButtonReceiver) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onAddressedPlayerChanged(mediaButtonReceiver);
+                }
+            });
+        }
+    }
 }
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index 3831cf7..dbfeefd 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -104,7 +104,6 @@
 
                     case ObexHelper.OBEX_OPCODE_DISCONNECT:
                         handleDisconnectRequest();
-                        done = true;
                         break;
 
                     case ObexHelper.OBEX_OPCODE_GET:
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e450283..2ef1cf5 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -33,6 +33,7 @@
         <receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
             <intent-filter>
                 <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
+                <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
             </intent-filter>
         </receiver>
         <service android:name="com.android.carrierdefaultapp.ProvisionObserver"
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
index e1125d9..d5d0b79 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
@@ -91,6 +91,10 @@
                     arg1 = intent.getStringExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY);
                     arg2 = intent.getStringExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY);
                     break;
+                case TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET:
+                    configs = b.getStringArray(CarrierConfigManager
+                            .KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET);
+                    break;
                 default:
                     Rlog.e(TAG, "load carrier config failure with un-configured key: " +
                             intent.getAction());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index cdfdad4..267dd3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -188,9 +188,16 @@
         if (mIcon == null) {
             return false;
         }
-        Drawable drawable = getIcon(mIcon);
+        Drawable drawable;
+        try {
+            drawable = getIcon(mIcon);
+        } catch (OutOfMemoryError e) {
+            Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
+            return false;
+        }
+
         if (drawable == null) {
-            Log.w(TAG, "No icon for slot " + mSlot);
+            Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
             return false;
         }
         if (withClear) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 03c46e8..024c1a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -223,8 +223,7 @@
 
         String contentDescription = getStringIfExists(getContentDescription());
         String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
-        final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
-                && mCurrentState.userSetup;
+        final boolean dataDisabled = isDataDisabled() && mCurrentState.userSetup;
 
         // Show icon in QS when we are connected or data is disabled.
         boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
@@ -404,7 +403,7 @@
         mCurrentState.roaming = isRoaming();
         if (isCarrierNetworkChangeActive()) {
             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
-        } else if (isDataDisabled()) {
+        } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
             mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
         }
         if (isEmergencyOnly() != mCurrentState.isEmergency) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2f7cd00..dd1a4c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -28,7 +28,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.PersistableBundle;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -219,6 +221,7 @@
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         mContext.registerReceiver(this, filter, null, mReceiverHandler);
         mListening = true;
 
@@ -396,6 +399,14 @@
                 // emergency state.
                 recalculateEmergency();
             }
+        } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+            mConfig = Config.readConfig(mContext);
+            mReceiverHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleConfigurationChanged();
+                }
+            });
         } else {
             int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
@@ -904,6 +915,7 @@
         boolean show4gForLte = false;
         boolean hideLtePlus = false;
         boolean hspaDataDistinguishable;
+        boolean alwaysShowDataRatIcon = false;
 
         static Config readConfig(Context context) {
             Config config = new Config();
@@ -916,6 +928,14 @@
             config.hspaDataDistinguishable =
                     res.getBoolean(R.bool.config_hspa_data_distinguishable);
             config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
+
+            CarrierConfigManager configMgr = (CarrierConfigManager)
+                    context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            PersistableBundle b = configMgr.getConfig();
+            if (b != null) {
+                config.alwaysShowDataRatIcon = b.getBoolean(
+                        CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
+            }
             return config;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index fce1172..93e1e6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -110,6 +110,21 @@
         verifyDataIndicators(0, 0);
     }
 
+    public void testAlwaysShowDataRatIcon() {
+        setupDefaultSignal();
+        Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+        updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
+                TelephonyManager.NETWORK_TYPE_GSM);
+
+        // Switch to showing data RAT icon when data is diconnected
+        // and re-initialize the NetworkController.
+        mConfig.alwaysShowDataRatIcon = true;
+        mNetworkController.handleConfigurationChanged();
+
+        verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_G);
+    }
+
     public void test4gDataIconConfigChange() {
         setupDefaultSignal();
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlur.java b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
index 7a702e8..a36873e 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlur.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
@@ -59,6 +59,9 @@
      * @param ain The input allocation
      */
     public void setInput(Allocation ain) {
+        if (ain.getType().getY() == 0) {
+            throw new RSIllegalArgumentException("Input set to a 1D Allocation");
+        }
         mInput = ain;
         setVar(1, ain);
     }
@@ -85,6 +88,9 @@
      *             type.
      */
     public void forEach(Allocation aout) {
+        if (aout.getType().getY() == 0) {
+            throw new RSIllegalArgumentException("Output is a 1D Allocation");
+        }
         forEach(0, (Allocation) null, aout, null);
     }
 
@@ -97,6 +103,9 @@
      * @param opt LaunchOptions for clipping
      */
     public void forEach(Allocation aout, Script.LaunchOptions opt) {
+        if (aout.getType().getY() == 0) {
+            throw new RSIllegalArgumentException("Output is a 1D Allocation");
+        }
         forEach(0, (Allocation) null, aout, null, opt);
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index de4734f..1262d88 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -307,6 +307,14 @@
                 if (newName != null) {
                     storeNameAndAddress(newName, null);
                 }
+            } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) {
+                String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS);
+                if (newAddress != null) {
+                    if (DBG) Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
+                    storeNameAndAddress(null, newAddress);
+                } else {
+                    if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found");
+                }
             }
         }
     };
@@ -343,6 +351,9 @@
         IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
         filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         mContext.registerReceiver(mReceiver, filter);
+        filter = new IntentFilter(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
+        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+        mContext.registerReceiver(mReceiver, filter);
         loadStoredNameAndAddress();
         if (isBluetoothPersistedStateOn()) {
             if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
@@ -1485,16 +1496,6 @@
                             if (mGetNameAddressOnly) return;
                         }
 
-                        try {
-                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
-                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
-                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
-                                Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
-                            }
-                        } catch (RemoteException e) {
-                            Slog.e(TAG,"Unable to call configHciSnoopLog", e);
-                        }
-
                         //Register callback object
                         try {
                             mBluetooth.registerCallback(mBluetoothCallback);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a2293a7..88bc54d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -36,6 +36,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.uidRulesToString;
+import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
@@ -48,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;
@@ -69,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;
@@ -92,6 +93,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -108,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;
@@ -376,11 +377,6 @@
     private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
 
     /**
-     * used to specify whether a network should not be penalized when it becomes unvalidated.
-     */
-    private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
-
-    /**
      * used to ask the user to confirm a connection to an unvalidated network.
      * obj  = network
      */
@@ -397,6 +393,16 @@
      */
     private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
 
+    /**
+     * used to specify whether a network should not be penalized when it becomes unvalidated.
+     */
+    private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
+
+    /**
+     * used to trigger revalidation of a network.
+     */
+    private static final int EVENT_REVALIDATE_NETWORK = 36;
+
     private static String eventName(int what) {
         return sMagicDecoderRing.get(what, Integer.toString(what));
     }
@@ -869,8 +875,8 @@
     }
 
     private void handleMobileDataAlwaysOn() {
-        final boolean enable = (Settings.Global.getInt(
-                mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1) == 1);
+        final boolean enable = toBool(Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1));
         final boolean isEnabled = (mNetworkRequests.get(mDefaultMobileDataRequest) != null);
         if (enable == isEnabled) {
             return;  // Nothing to do.
@@ -2223,7 +2229,7 @@
                 }
                 case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
                     final int netId = msg.arg2;
-                    final boolean visible = (msg.arg1 != 0);
+                    final boolean visible = toBool(msg.arg1);
                     final NetworkAgentInfo nai;
                     synchronized (mNetworkForNetId) {
                         nai = mNetworkForNetId.get(netId);
@@ -2549,25 +2555,32 @@
     }
 
     private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
-        if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
-                nri.request.requestId) == null) {
-            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL);
+        if (mNetworkRequests.get(nri.request) == null) {
+            return;
         }
+        if (mNetworkForRequestId.get(nri.request.requestId) != null) {
+            return;
+        }
+        if (VDBG || (DBG && nri.request.isRequest())) {
+            log("releasing " + nri.request + " (timeout)");
+        }
+        handleRemoveNetworkRequest(nri);
+        callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
     }
 
     private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
-        final NetworkRequestInfo nri = getNriForAppRequest(
-                request, callingUid, "release NetworkRequest");
-        if (nri != null) {
-            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED);
+        final NetworkRequestInfo nri =
+                getNriForAppRequest(request, callingUid, "release NetworkRequest");
+        if (nri == null) {
+            return;
         }
+        if (VDBG || (DBG && nri.request.isRequest())) {
+            log("releasing " + nri.request + " (release request)");
+        }
+        handleRemoveNetworkRequest(nri);
     }
 
-    private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) {
-        final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
-        if (VDBG || (DBG && nri.request.isRequest())) {
-            log("releasing " + nri.request + " (" + logCallbackType + ")");
-        }
+    private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
         nri.unlinkDeathRecipient();
         mNetworkRequests.remove(nri.request);
         synchronized (mUidToNetworkRequestCount) {
@@ -2663,14 +2676,13 @@
                 }
             }
         }
-        callCallbackForRequest(nri, null, whichCallback, 0);
     }
 
     @Override
     public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
         enforceConnectivityInternalPermission();
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_UNVALIDATED,
-                accept ? 1 : 0, always ? 1: 0, network));
+                encodeBool(accept), encodeBool(always), network));
     }
 
     @Override
@@ -2707,7 +2719,7 @@
 
         if (always) {
             nai.asyncChannel.sendMessage(
-                    NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, accept ? 1 : 0);
+                    NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept));
         }
 
         if (!accept) {
@@ -2908,7 +2920,8 @@
                     break;
                 }
                 case EVENT_SET_ACCEPT_UNVALIDATED: {
-                    handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0);
+                    Network network = (Network) msg.obj;
+                    handleSetAcceptUnvalidated(network, toBool(msg.arg1), toBool(msg.arg2));
                     break;
                 }
                 case EVENT_SET_AVOID_UNVALIDATED: {
@@ -2942,14 +2955,18 @@
                     }
                     break;
                 }
+                case EVENT_REVALIDATE_NETWORK: {
+                    handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
+                    break;
+                }
             }
         }
     }
 
     // javadoc from interface
     @Override
-    public int tether(String iface) {
-        ConnectivityManager.enforceTetherChangePermission(mContext);
+    public int tether(String iface, String callerPkg) {
+        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         if (isTetheringSupported()) {
             final int status = mTethering.tether(iface);
             return status;
@@ -2960,8 +2977,8 @@
 
     // javadoc from interface
     @Override
-    public int untether(String iface) {
-        ConnectivityManager.enforceTetherChangePermission(mContext);
+    public int untether(String iface, String callerPkg) {
+        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
 
         if (isTetheringSupported()) {
             final int status = mTethering.untether(iface);
@@ -3015,8 +3032,8 @@
     }
 
     @Override
-    public int setUsbTethering(boolean enable) {
-        ConnectivityManager.enforceTetherChangePermission(mContext);
+    public int setUsbTethering(boolean enable, String callerPkg) {
+        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         if (isTetheringSupported()) {
             return mTethering.setUsbTethering(enable);
         } else {
@@ -3056,9 +3073,10 @@
     @Override
     public boolean isTetheringSupported() {
         enforceTetherAccessPermission();
-        int defaultVal = (mSystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
-        boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.TETHER_SUPPORTED, defaultVal) != 0)
+        int defaultVal = encodeBool(!mSystemProperties.get("ro.tether.denied").equals("true"));
+        boolean tetherSupported = toBool(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.TETHER_SUPPORTED, defaultVal));
+        boolean tetherEnabledInSettings = tetherSupported
                 && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
 
         // Elevate to system UID to avoid caller requiring MANAGE_USERS permission.
@@ -3070,13 +3088,13 @@
             Binder.restoreCallingIdentity(token);
         }
 
-        return tetherEnabledInSettings && adminUser &&
-               mTethering.hasTetherableConfiguration();
+        return tetherEnabledInSettings && adminUser && mTethering.hasTetherableConfiguration();
     }
 
     @Override
-    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
-        ConnectivityManager.enforceTetherChangePermission(mContext);
+    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
+            String callerPkg) {
+        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         if (!isTetheringSupported()) {
             receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
             return;
@@ -3085,8 +3103,8 @@
     }
 
     @Override
-    public void stopTethering(int type) {
-        ConnectivityManager.enforceTetherChangePermission(mContext);
+    public void stopTethering(int type, String callerPkg) {
+        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         mTethering.stopTethering(type);
     }
 
@@ -3148,8 +3166,14 @@
     public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
         enforceAccessPermission();
         enforceInternetPermission();
+        final int uid = Binder.getCallingUid();
+        final int connectivityInfo = encodeBool(hasConnectivity);
+        mHandler.sendMessage(
+                mHandler.obtainMessage(EVENT_REVALIDATE_NETWORK, uid, connectivityInfo, network));
+    }
 
-        // TODO: execute this logic on ConnectivityService handler.
+    private void handleReportNetworkConnectivity(
+            Network network, int uid, boolean hasConnectivity) {
         final NetworkAgentInfo nai;
         if (network == null) {
             nai = getDefaultNetwork();
@@ -3164,10 +3188,9 @@
         if (hasConnectivity == nai.lastValidated) {
             return;
         }
-        final int uid = Binder.getCallingUid();
         if (DBG) {
-            log("reportNetworkConnectivity(" + nai.network.netId + ", " + hasConnectivity +
-                    ") by " + uid);
+            int netid = nai.network.netId;
+            log("reportNetworkConnectivity(" + netid + ", " + hasConnectivity + ") by " + uid);
         }
         // Validating a network that has not yet connected could result in a call to
         // rematchNetworkAndRequests() which is not meant to work on such networks.
@@ -3450,13 +3473,6 @@
         Slog.e(TAG, s);
     }
 
-    private static <T> T checkNotNull(T value, String message) {
-        if (value == null) {
-            throw new NullPointerException(message);
-        }
-        return value;
-    }
-
     /**
      * Prepare for a VPN application.
      * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
@@ -3679,17 +3695,9 @@
             existing.shutdown();
         }
 
-        try {
-            if (tracker != null) {
-                mNetd.setFirewallEnabled(true);
-                mNetd.setFirewallInterfaceRule("lo", true);
-                mLockdownTracker = tracker;
-                mLockdownTracker.init();
-            } else {
-                mNetd.setFirewallEnabled(false);
-            }
-        } catch (RemoteException e) {
-            // ignored; NMS lives inside system_server
+        if (tracker != null) {
+            mLockdownTracker = tracker;
+            mLockdownTracker.init();
         }
     }
 
@@ -3885,7 +3893,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             final ContentResolver cr = mContext.getContentResolver();
-            Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
+            Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, encodeBool(enable));
             Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
             intent.putExtra("state", enable);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
@@ -4122,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) {
@@ -4147,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);
@@ -4221,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);
@@ -4285,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);
@@ -4305,9 +4319,7 @@
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
         }
-
-        MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
-                networkCapabilities.getNetworkSpecifier());
+        ensureValidNetworkSpecifier(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(
                 new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
@@ -4728,16 +4740,17 @@
         releasePendingNetworkRequestWithDelay(pendingIntent);
     }
 
-    private void callCallbackForRequest(NetworkRequestInfo nri,
+    private static void callCallbackForRequest(NetworkRequestInfo nri,
             NetworkAgentInfo networkAgent, int notificationType, int arg1) {
-        if (nri.messenger == null) return;  // Default request has no msgr
+        if (nri.messenger == null) {
+            return;  // Default request has no msgr
+        }
         Bundle bundle = new Bundle();
-        bundle.putParcelable(NetworkRequest.class.getSimpleName(),
-                new NetworkRequest(nri.request));
+        // TODO: check if defensive copies of data is needed.
+        putParcelable(bundle, new NetworkRequest(nri.request));
         Message msg = Message.obtain();
-        if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL &&
-                notificationType != ConnectivityManager.CALLBACK_RELEASED) {
-            bundle.putParcelable(Network.class.getSimpleName(), networkAgent.network);
+        if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
+            putParcelable(bundle, networkAgent.network);
         }
         switch (notificationType) {
             case ConnectivityManager.CALLBACK_LOSING: {
@@ -4745,13 +4758,11 @@
                 break;
             }
             case ConnectivityManager.CALLBACK_CAP_CHANGED: {
-                bundle.putParcelable(NetworkCapabilities.class.getSimpleName(),
-                        new NetworkCapabilities(networkAgent.networkCapabilities));
+                putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
                 break;
             }
             case ConnectivityManager.CALLBACK_IP_CHANGED: {
-                bundle.putParcelable(LinkProperties.class.getSimpleName(),
-                        new LinkProperties(networkAgent.linkProperties));
+                putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
                 break;
             }
         }
@@ -4759,8 +4770,8 @@
         msg.setData(bundle);
         try {
             if (VDBG) {
-                log("sending notification " + notifyTypeToName(notificationType) +
-                        " for " + nri.request);
+                String notification = ConnectivityManager.getCallbackName(notificationType);
+                log("sending notification " + notification + " for " + nri.request);
             }
             nri.messenger.send(msg);
         } catch (RemoteException e) {
@@ -4769,6 +4780,10 @@
         }
     }
 
+    private static <T extends Parcelable> void putParcelable(Bundle bundle, T t) {
+        bundle.putParcelable(t.getClass().getSimpleName(), t);
+    }
+
     private void teardownUnneededNetwork(NetworkAgentInfo nai) {
         if (nai.numRequestNetworkRequests() != 0) {
             for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -5370,7 +5385,10 @@
     }
 
     protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType, int arg1) {
-        if (VDBG) log("notifyType " + notifyTypeToName(notifyType) + " for " + networkAgent.name());
+        if (VDBG) {
+            String notification = ConnectivityManager.getCallbackName(notifyType);
+            log("notifyType " + notification + " for " + networkAgent.name());
+        }
         for (int i = 0; i < networkAgent.numNetworkRequests(); i++) {
             NetworkRequest nr = networkAgent.requestAt(i);
             NetworkRequestInfo nri = mNetworkRequests.get(nr);
@@ -5389,20 +5407,6 @@
         notifyNetworkCallbacks(networkAgent, notifyType, 0);
     }
 
-    private String notifyTypeToName(int notifyType) {
-        switch (notifyType) {
-            case ConnectivityManager.CALLBACK_PRECHECK:    return "PRECHECK";
-            case ConnectivityManager.CALLBACK_AVAILABLE:   return "AVAILABLE";
-            case ConnectivityManager.CALLBACK_LOSING:      return "LOSING";
-            case ConnectivityManager.CALLBACK_LOST:        return "LOST";
-            case ConnectivityManager.CALLBACK_UNAVAIL:     return "UNAVAILABLE";
-            case ConnectivityManager.CALLBACK_CAP_CHANGED: return "CAP_CHANGED";
-            case ConnectivityManager.CALLBACK_IP_CHANGED:  return "IP_CHANGED";
-            case ConnectivityManager.CALLBACK_RELEASED:    return "RELEASED";
-        }
-        return "UNKNOWN";
-    }
-
     /**
      * Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
      * properties tracked by NetworkStatsService on an active iface has changed.
@@ -5482,8 +5486,9 @@
 
         if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
             // Untether
+            String pkgName = mContext.getOpPackageName();
             for (String tether : getTetheredIfaces()) {
-                untether(tether);
+                untether(tether, pkgName);
             }
         }
 
@@ -5568,4 +5573,12 @@
     private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
         mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
     }
+
+    private static boolean toBool(int encodedBoolean) {
+        return encodedBoolean != 0; // Only 0 means false.
+    }
+
+    private static int encodeBool(boolean b) {
+        return b ? 1 : 0;
+    }
 }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 87938cb..7e1a1ca 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -95,7 +95,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.NativeDaemonConnector.Command;
 import com.android.server.NativeDaemonConnector.SensitiveArg;
-import com.android.server.net.LockdownVpnTracker;
 import com.google.android.collect.Maps;
 
 import java.io.BufferedReader;
@@ -628,7 +627,7 @@
                 }
             }
 
-            setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
+            setFirewallEnabled(mFirewallEnabled);
 
             syncFirewallChainLocked(FIREWALL_CHAIN_NONE, mUidFirewallRules, "");
             syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, mUidFirewallStandbyRules, "standby ");
@@ -1897,30 +1896,6 @@
         }
     }
 
-    @Override
-    public void setFirewallEgressSourceRule(String addr, boolean allow) {
-        enforceSystemUid();
-        Preconditions.checkState(mFirewallEnabled);
-        final String rule = allow ? "allow" : "deny";
-        try {
-            mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
-        enforceSystemUid();
-        Preconditions.checkState(mFirewallEnabled);
-        final String rule = allow ? "allow" : "deny";
-        try {
-            mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
     private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
         // UID ranges to close sockets on.
         UidRange[] ranges;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index a691af9..55bca64 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -26,6 +26,8 @@
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
 import android.os.Binder;
+import android.os.HandlerThread;
+import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.UserHandle;
@@ -37,9 +39,11 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.InetAddress;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
@@ -59,10 +63,10 @@
     private static final boolean DBG = true;
 
     private final Context mContext;
-    private final ContentResolver mContentResolver;
+    private final NsdSettings mNsdSettings;
     private final NsdStateMachine mNsdStateMachine;
-    private final NativeDaemonConnector mNativeConnector;
-    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
+    private final DaemonConnection mDaemon;
+    private final NativeCallbackReceiver mDaemonCallback;
 
     /**
      * Clients receiving asynchronous messages
@@ -108,8 +112,8 @@
                     false, contentObserver);
         }
 
-        NsdStateMachine(String name) {
-            super(name);
+        NsdStateMachine(String name, Handler handler) {
+            super(name, handler);
             addState(mDefaultState);
                 addState(mDisabledState, mDefaultState);
                 addState(mEnabledState, mDefaultState);
@@ -541,36 +545,35 @@
         return sb.toString();
     }
 
-    private NsdService(Context context) {
-        mContext = context;
-        mContentResolver = context.getContentResolver();
-
-        mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
-                MDNS_TAG, 25, null);
-
-        mNsdStateMachine = new NsdStateMachine(TAG);
+    @VisibleForTesting
+    NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) {
+        mContext = ctx;
+        mNsdSettings = settings;
+        mNsdStateMachine = new NsdStateMachine(TAG, handler);
         mNsdStateMachine.start();
-
-        Thread th = new Thread(mNativeConnector, MDNS_TAG);
-        th.start();
+        mDaemonCallback = new NativeCallbackReceiver();
+        mDaemon = fn.get(mDaemonCallback);
     }
 
     public static NsdService create(Context context) throws InterruptedException {
-        NsdService service = new NsdService(context);
-        service.mNativeDaemonConnected.await();
+        NsdSettings settings = NsdSettings.makeDefault(context);
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        Handler handler = new Handler(thread.getLooper());
+        NsdService service = new NsdService(context, settings, handler, DaemonConnection::new);
+        service.mDaemonCallback.awaitConnection();
         return service;
     }
 
     public Messenger getMessenger() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
-            "NsdService");
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
         return new Messenger(mNsdStateMachine.getHandler());
     }
 
     public void setEnabled(boolean enable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
                 "NsdService");
-        Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
+        mNsdSettings.putEnabledStatus(enable);
         if (enable) {
             mNsdStateMachine.sendMessage(NsdManager.ENABLE);
         } else {
@@ -590,8 +593,10 @@
     }
 
     private boolean isNsdEnabled() {
-        boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
-        if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
+        boolean ret = mNsdSettings.isEnabled();
+        if (DBG) {
+            Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled"));
+        }
         return ret;
     }
 
@@ -655,14 +660,23 @@
     }
 
     class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
-        public void onDaemonConnected() {
-            mNativeDaemonConnected.countDown();
+        private final CountDownLatch connected = new CountDownLatch(1);
+
+        public void awaitConnection() throws InterruptedException {
+            connected.await();
         }
 
+        @Override
+        public void onDaemonConnected() {
+            connected.countDown();
+        }
+
+        @Override
         public boolean onCheckHoldWakeLock(int code) {
             return false;
         }
 
+        @Override
         public boolean onEvent(int code, String raw, String[] cooked) {
             // TODO: NDC translates a message to a callback, we could enhance NDC to
             // directly interact with a state machine through messages
@@ -672,132 +686,102 @@
         }
     }
 
-    private boolean startMDnsDaemon() {
-        if (DBG) Slog.d(TAG, "startMDnsDaemon");
-        try {
-            mNativeConnector.execute("mdnssd", "start-service");
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to start daemon" + e);
-            return false;
+    interface DaemonConnectionSupplier {
+        DaemonConnection get(NativeCallbackReceiver callback);
+    }
+
+    @VisibleForTesting
+    public static class DaemonConnection {
+        final NativeDaemonConnector mNativeConnector;
+
+        DaemonConnection(NativeCallbackReceiver callback) {
+            mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
+            new Thread(mNativeConnector, MDNS_TAG).start();
         }
-        return true;
+
+        public boolean execute(Object... args) {
+            if (DBG) {
+                Slog.d(TAG, "mdnssd " + Arrays.toString(args));
+            }
+            try {
+                mNativeConnector.execute("mdnssd", args);
+            } catch (NativeDaemonConnectorException e) {
+                Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
+                return false;
+            }
+            return true;
+        }
+
+        public boolean execute(Command cmd) {
+            if (DBG) {
+                Slog.d(TAG, cmd.toString());
+            }
+            try {
+                mNativeConnector.execute(cmd);
+            } catch (NativeDaemonConnectorException e) {
+                Slog.e(TAG, "Failed to execute " + cmd, e);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private boolean startMDnsDaemon() {
+        return mDaemon.execute("start-service");
     }
 
     private boolean stopMDnsDaemon() {
-        if (DBG) Slog.d(TAG, "stopMDnsDaemon");
-        try {
-            mNativeConnector.execute("mdnssd", "stop-service");
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to start daemon" + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("stop-service");
     }
 
     private boolean registerService(int regId, NsdServiceInfo service) {
-        if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
-        try {
-            Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
-                    service.getServiceType(), service.getPort(),
-                    Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT)
-                            .replace("\n", ""));
-
-            mNativeConnector.execute(cmd);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to execute registerService " + e);
-            return false;
+        if (DBG) {
+            Slog.d(TAG, "registerService: " + regId + " " + service);
         }
-        return true;
+        String name = service.getServiceName();
+        String type = service.getServiceType();
+        int port = service.getPort();
+        byte[] textRecord = service.getTxtRecord();
+        String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", "");
+        Command cmd = new Command("mdnssd", "register", regId, name, type, port, record);
+        return mDaemon.execute(cmd);
     }
 
     private boolean unregisterService(int regId) {
-        if (DBG) Slog.d(TAG, "unregisterService: " + regId);
-        try {
-            mNativeConnector.execute("mdnssd", "stop-register", regId);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to execute unregisterService " + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("stop-register", regId);
     }
 
     private boolean updateService(int regId, DnsSdTxtRecord t) {
-        if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
-        try {
-            if (t == null) return false;
-            mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to updateServices " + e);
+        if (t == null) {
             return false;
         }
-        return true;
+        return mDaemon.execute("update", regId, t.size(), t.getRawData());
     }
 
     private boolean discoverServices(int discoveryId, String serviceType) {
-        if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
-        try {
-            mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to discoverServices " + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("discover", discoveryId, serviceType);
     }
 
     private boolean stopServiceDiscovery(int discoveryId) {
-        if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
-        try {
-            mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("stop-discover", discoveryId);
     }
 
     private boolean resolveService(int resolveId, NsdServiceInfo service) {
-        if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
-        try {
-            mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
-                    service.getServiceType(), "local.");
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to resolveService " + e);
-            return false;
-        }
-        return true;
+        String name = service.getServiceName();
+        String type = service.getServiceType();
+        return mDaemon.execute("resolve", resolveId, name, type, "local.");
     }
 
     private boolean stopResolveService(int resolveId) {
-        if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
-        try {
-            mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to stop resolve " + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("stop-resolve", resolveId);
     }
 
     private boolean getAddrInfo(int resolveId, String hostname) {
-        if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
-        try {
-            mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to getAddrInfo " + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("getaddrinfo", resolveId, hostname);
     }
 
     private boolean stopGetAddrInfo(int resolveId) {
-        if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
-        try {
-            mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
-        } catch(NativeDaemonConnectorException e) {
-            Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
-            return false;
-        }
-        return true;
+        return mDaemon.execute("stop-getaddrinfo", resolveId);
     }
 
     @Override
@@ -927,4 +911,25 @@
             return -1;
         }
     }
+
+    @VisibleForTesting
+    public interface NsdSettings {
+        boolean isEnabled();
+        void putEnabledStatus(boolean isEnabled);
+
+        static NsdSettings makeDefault(Context context) {
+            ContentResolver resolver = context.getContentResolver();
+            return new NsdSettings() {
+                @Override
+                public boolean isEnabled() {
+                    return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1;
+                }
+
+                @Override
+                public void putEnabledStatus(boolean isEnabled) {
+                    Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
+                }
+            };
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5ae4d67..c5fc038 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5324,35 +5324,61 @@
         return tracesFile;
     }
 
+    public static class DumpStackFileObserver extends FileObserver {
+        // Keep in sync with frameworks/native/cmds/dumpstate/utils.cpp
+        private static final int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
+        static final int TRACE_DUMP_TIMEOUT_SECONDS = TRACE_DUMP_TIMEOUT_MS / 1000;
+
+        private final String mTracesPath;
+        private boolean mClosed;
+
+        public DumpStackFileObserver(String tracesPath) {
+            super(tracesPath, FileObserver.CLOSE_WRITE);
+            mTracesPath = tracesPath;
+        }
+
+        @Override
+        public synchronized void onEvent(int event, String path) {
+            mClosed = true;
+            notify();
+        }
+
+        public void dumpWithTimeout(int pid) {
+            Process.sendSignal(pid, Process.SIGNAL_QUIT);
+            synchronized (this) {
+                try {
+                    wait(TRACE_DUMP_TIMEOUT_MS); // Wait for traces file to be closed.
+                } catch (InterruptedException e) {
+                    Slog.wtf(TAG, e);
+                }
+            }
+            if (!mClosed) {
+                Slog.w(TAG, "Didn't see close of " + mTracesPath + " for pid " + pid +
+                       ". Attempting native stack collection.");
+                Debug.dumpNativeBacktraceToFileTimeout(pid, mTracesPath, TRACE_DUMP_TIMEOUT_SECONDS);
+            }
+            mClosed = false;
+        }
+    }
+
     private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
             ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
         // Use a FileObserver to detect when traces finish writing.
         // The order of traces is considered important to maintain for legibility.
-        FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
-            @Override
-            public synchronized void onEvent(int event, String path) { notify(); }
-        };
-
+        DumpStackFileObserver observer = new DumpStackFileObserver(tracesPath);
         try {
             observer.startWatching();
 
             // First collect all of the stacks of the most important pids.
             if (firstPids != null) {
-                try {
-                    int num = firstPids.size();
-                    for (int i = 0; i < num; i++) {
-                        synchronized (observer) {
-                            if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
-                                    + firstPids.get(i));
-                            final long sime = SystemClock.elapsedRealtime();
-                            Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
-                            observer.wait(1000);  // Wait for write-close, give up after 1 sec
-                            if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
-                                    + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
-                        }
-                    }
-                } catch (InterruptedException e) {
-                    Slog.wtf(TAG, e);
+                int num = firstPids.size();
+                for (int i = 0; i < num; i++) {
+                    if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
+                            + firstPids.get(i));
+                    final long sime = SystemClock.elapsedRealtime();
+                    observer.dumpWithTimeout(firstPids.get(i));
+                    if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
+                            + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                 }
             }
 
@@ -5364,7 +5390,8 @@
                         if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
                         final long sime = SystemClock.elapsedRealtime();
 
-                        Debug.dumpNativeBacktraceToFileTimeout(pid, tracesPath, 10);
+                        Debug.dumpNativeBacktraceToFileTimeout(
+                                pid, tracesPath, DumpStackFileObserver.TRACE_DUMP_TIMEOUT_SECONDS);
                         if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
                                 + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                     }
@@ -5391,19 +5418,12 @@
                     ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
                     if (lastPids.indexOfKey(stats.pid) >= 0) {
                         numProcs++;
-                        try {
-                            synchronized (observer) {
-                                if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
-                                        + stats.pid);
-                                final long stime = SystemClock.elapsedRealtime();
-                                Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
-                                observer.wait(1000);  // Wait for write-close, give up after 1 sec
-                                if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
-                                        + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
-                            }
-                        } catch (InterruptedException e) {
-                            Slog.wtf(TAG, e);
-                        }
+                        if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
+                                + stats.pid);
+                        final long stime = SystemClock.elapsedRealtime();
+                        observer.dumpWithTimeout(stats.pid);
+                        if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
+                                + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
                     } else if (DEBUG_ANR) {
                         Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
                                 + stats.pid);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 71c7fd3..2e74eb9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -493,8 +493,9 @@
                                         Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                 runningIntent.setData(Uri.fromParts("package",
                                         appInfo.packageName, null));
-                                PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
-                                        runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                                PendingIntent pi = PendingIntent.getActivityAsUser(ams.mContext, 0,
+                                        runningIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
+                                        UserHandle.of(userId));
                                 notiBuilder.setColor(ams.mContext.getColor(
                                         com.android.internal
                                                 .R.color.system_notification_accent_color));
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 460d5f9..9edc35e 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -136,7 +136,7 @@
         public boolean isCurrentlyServing() {
             switch (lastState) {
                 case IControlsTethering.STATE_TETHERED:
-                case IControlsTethering.STATE_LOCAL_HOTSPOT:
+                case IControlsTethering.STATE_LOCAL_ONLY:
                     return true;
                 default:
                     return false;
@@ -219,6 +219,10 @@
         return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
+    private WifiManager getWifiManager() {
+        return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+    }
+
     private void updateConfiguration() {
         mConfig = new TetheringConfiguration(mContext);
     }
@@ -409,15 +413,21 @@
     }
 
     private int setWifiTethering(final boolean enable) {
-        synchronized (mPublicSync) {
-            mWifiTetherRequested = enable;
-            final WifiManager wifiManager =
-                    (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-            if (wifiManager.setWifiApEnabled(null /* use existing wifi config */, enable)) {
-                return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+        int rval = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mPublicSync) {
+                mWifiTetherRequested = enable;
+                final WifiManager mgr = getWifiManager();
+                if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
+                    (!enable && mgr.stopSoftAp())) {
+                    rval = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+                }
             }
-            return ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
+        return rval;
     }
 
     private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
@@ -623,9 +633,10 @@
     private void sendTetherStateChangedBroadcast() {
         if (!getConnectivityManager().isTetheringSupported()) return;
 
-        ArrayList<String> availableList = new ArrayList<String>();
-        ArrayList<String> activeList = new ArrayList<String>();
-        ArrayList<String> erroredList = new ArrayList<String>();
+        final ArrayList<String> availableList = new ArrayList<>();
+        final ArrayList<String> tetherList = new ArrayList<>();
+        final ArrayList<String> localOnlyList = new ArrayList<>();
+        final ArrayList<String> erroredList = new ArrayList<>();
 
         boolean wifiTethered = false;
         boolean usbTethered = false;
@@ -641,6 +652,8 @@
                     erroredList.add(iface);
                 } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
                     availableList.add(iface);
+                } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) {
+                    localOnlyList.add(iface);
                 } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
                     if (cfg.isUsb(iface)) {
                         usbTethered = true;
@@ -649,25 +662,25 @@
                     } else if (cfg.isBluetooth(iface)) {
                         bluetoothTethered = true;
                     }
-                    activeList.add(iface);
+                    tetherList.add(iface);
                 }
             }
         }
-        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
-        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+        final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
-                availableList);
-        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
-        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
-                erroredList);
-        mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
+        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList);
+        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
+        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList);
+        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList);
+        mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
         if (DBG) {
             Log.d(TAG, String.format(
-                    "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]",
-                    TextUtils.join(",", availableList),
-                    TextUtils.join(",", activeList),
-                    TextUtils.join(",", erroredList)));
+                    "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
+                    "avail", TextUtils.join(",", availableList),
+                    "local_only", TextUtils.join(",", localOnlyList),
+                    "tether", TextUtils.join(",", tetherList),
+                    "error", TextUtils.join(",", erroredList)));
         }
 
         if (usbTethered) {
@@ -803,7 +816,7 @@
                         // Otherwise, assume it's a local-only hotspot request.
                         final int state = mWifiTetherRequested
                                 ? IControlsTethering.STATE_TETHERED
-                                : IControlsTethering.STATE_LOCAL_HOTSPOT;
+                                : IControlsTethering.STATE_LOCAL_ONLY;
                         tetherMatchingInterfaces(state, ConnectivityManager.TETHERING_WIFI);
                         break;
                     case WifiManager.WIFI_AP_STATE_DISABLED:
@@ -873,7 +886,7 @@
                 result = untether(chosenIface);
                 break;
             case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_HOTSPOT:
+            case IControlsTethering.STATE_LOCAL_ONLY:
                 result = tether(chosenIface, requestedState);
                 break;
             default:
@@ -1330,15 +1343,40 @@
             } else {
                 mForwardedDownstreams.remove(who);
             }
+
+            // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
+            if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+                final WifiManager mgr = getWifiManager();
+                final String iface = who.interfaceName();
+                switch (mode) {
+                    case IControlsTethering.STATE_TETHERED:
+                        mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_TETHERED);
+                        break;
+                    case IControlsTethering.STATE_LOCAL_ONLY:
+                        mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+                        break;
+                    default:
+                        Log.wtf(TAG, "Unknown active serving mode: " + mode);
+                        break;
+                }
+            }
         }
 
         private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
             mNotifyList.remove(who);
             mIPv6TetheringCoordinator.removeActiveDownstream(who);
             mForwardedDownstreams.remove(who);
+
+            // If this is a Wi-Fi interface, tell WifiManager of any errors.
+            if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+                if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                    getWifiManager().updateInterfaceIpState(
+                            who.interfaceName(), WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+                }
+            }
         }
 
-        class InitialState extends TetherMasterUtilState {
+        class InitialState extends State {
             @Override
             public boolean processMessage(Message message) {
                 maybeLogMessage(this, message.what);
@@ -1516,7 +1554,8 @@
         }
 
         class ErrorState extends State {
-            int mErrorNotification;
+            private int mErrorNotification;
+
             @Override
             public boolean processMessage(Message message) {
                 boolean retValue = true;
@@ -1534,6 +1573,7 @@
                 }
                 return retValue;
             }
+
             void notify(int msgType) {
                 mErrorNotification = msgType;
                 for (TetherInterfaceStateMachine sm : mNotifyList) {
@@ -1542,6 +1582,7 @@
             }
 
         }
+
         class SetIpForwardingEnabledErrorState extends ErrorState {
             @Override
             public void enter() {
@@ -1635,7 +1676,7 @@
                     case IControlsTethering.STATE_TETHERED:
                         pw.print("TetheredState");
                         break;
-                    case IControlsTethering.STATE_LOCAL_HOTSPOT:
+                    case IControlsTethering.STATE_LOCAL_ONLY:
                         pw.print("LocalHotspotState");
                         break;
                     default:
@@ -1654,7 +1695,7 @@
     public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
                                            int state, int error) {
         synchronized (mPublicSync) {
-            TetherState tetherState = mTetherStates.get(iface);
+            final TetherState tetherState = mTetherStates.get(iface);
             if (tetherState != null && tetherState.stateMachine.equals(who)) {
                 tetherState.lastState = state;
                 tetherState.lastError = error;
@@ -1690,7 +1731,7 @@
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
                 break;
             case IControlsTethering.STATE_TETHERED:
-            case IControlsTethering.STATE_LOCAL_HOTSPOT:
+            case IControlsTethering.STATE_LOCAL_ONLY:
                 which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
                 break;
             default:
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 584994a..5dc8640 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -264,6 +264,30 @@
     }
 
     /**
+     * Chooses whether to force all connections to go though VPN.
+     *
+     * Used to enable/disable legacy VPN lockdown.
+     *
+     * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
+     * previous settings from calling that function will be replaced and saved with the
+     * always-on state.
+     *
+     * @param lockdown whether to prevent all traffic outside of a VPN.
+     */
+    public synchronized void setLockdown(boolean lockdown) {
+        enforceControlPermissionOrInternalCaller();
+
+        setVpnForcedLocked(lockdown);
+        mLockdown = lockdown;
+
+        // Update app lockdown setting if it changed. Legacy VPN lockdown status is controlled by
+        // LockdownVpnTracker.isEnabled() which keeps track of its own state.
+        if (mAlwaysOn) {
+            saveAlwaysOnPackage();
+        }
+    }
+
+    /**
      * Configures an always-on VPN connection through a specific application.
      * This connection is automatically granted and persisted after a reboot.
      *
@@ -376,7 +400,7 @@
             mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
                     getAlwaysOnPackage(), mUserHandle);
             mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
-                    (mLockdown ? 1 : 0), mUserHandle);
+                    (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -557,6 +581,7 @@
             mConfig = null;
 
             updateState(DetailedState.IDLE, "prepare");
+            setVpnForcedLocked(mLockdown);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -1003,9 +1028,7 @@
                         Log.wtf(TAG, "Failed to add restricted user to owner", e);
                     }
                 }
-                if (mAlwaysOn) {
-                    setVpnForcedLocked(mLockdown);
-                }
+                setVpnForcedLocked(mLockdown);
             }
         }
     }
@@ -1022,9 +1045,7 @@
                         Log.wtf(TAG, "Failed to remove restricted user to owner", e);
                     }
                 }
-                if (mAlwaysOn) {
-                    setVpnForcedLocked(mLockdown);
-                }
+                setVpnForcedLocked(mLockdown);
             }
         }
     }
@@ -1034,7 +1055,7 @@
      */
     public synchronized void onUserStopped() {
         // Switch off networking lockdown (if it was enabled)
-        setVpnForcedLocked(false);
+        setLockdown(false);
         mAlwaysOn = false;
 
         unregisterPackageChangeReceiverLocked();
@@ -1061,20 +1082,31 @@
      */
     @GuardedBy("this")
     private void setVpnForcedLocked(boolean enforce) {
+        final List<String> exemptedPackages =
+                isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
+        setVpnForcedWithExemptionsLocked(enforce, exemptedPackages);
+    }
+
+    /**
+     * @see #setVpnForcedLocked
+     */
+    @GuardedBy("this")
+    private void setVpnForcedWithExemptionsLocked(boolean enforce,
+            @Nullable List<String> exemptedPackages) {
         final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
+
+        Set<UidRange> addedRanges = Collections.emptySet();
         if (enforce) {
-            final Set<UidRange> addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
+            addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
                     /* allowedApplications */ null,
-                    /* disallowedApplications */ Collections.singletonList(mPackage));
+                    /* disallowedApplications */ exemptedPackages);
 
             removedRanges.removeAll(addedRanges);
             addedRanges.removeAll(mBlockedUsers);
-
-            setAllowOnlyVpnForUids(false, removedRanges);
-            setAllowOnlyVpnForUids(true, addedRanges);
-        } else {
-            setAllowOnlyVpnForUids(false, removedRanges);
         }
+
+        setAllowOnlyVpnForUids(false, removedRanges);
+        setAllowOnlyVpnForUids(true, addedRanges);
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
index f3914b7..c5c86bd 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
@@ -23,9 +23,9 @@
  */
 public interface IControlsTethering {
     public final int STATE_UNAVAILABLE = 0;
-    public final int STATE_AVAILABLE = 1;
-    public final int STATE_TETHERED = 2;
-    public final int STATE_LOCAL_HOTSPOT = 3;
+    public final int STATE_AVAILABLE   = 1;
+    public final int STATE_TETHERED    = 2;
+    public final int STATE_LOCAL_ONLY  = 3;
 
     /**
      * Notify that |who| has changed its tethering state.  This may be called from any thread.
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 5f496ca..2485654 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -172,7 +172,7 @@
         final Downstream ds = findDownstream(sm);
         if (ds == null) return null;
 
-        if (ds.mode == IControlsTethering.STATE_LOCAL_HOTSPOT) {
+        if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
             // Build a Unique Locally-assigned Prefix configuration.
             return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
         }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 601ed01..d3cfd87 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -117,9 +117,11 @@
         setInitialState(mInitialState);
     }
 
-    public int interfaceType() {
-        return mInterfaceType;
-    }
+    public String interfaceName() { return mIfaceName; }
+
+    public int interfaceType() { return mInterfaceType; }
+
+    public int lastError() { return mLastError; }
 
     // configured when we start tethering and unconfig'd on error or conclusion
     private boolean configureIfaceIp(boolean enabled) {
@@ -194,7 +196,7 @@
                 case CMD_TETHER_REQUESTED:
                     mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
                     switch (message.arg1) {
-                        case IControlsTethering.STATE_LOCAL_HOTSPOT:
+                        case IControlsTethering.STATE_LOCAL_ONLY:
                             transitionTo(mLocalHotspotState);
                             break;
                         case IControlsTethering.STATE_TETHERED:
@@ -304,7 +306,7 @@
             }
 
             if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
-            sendInterfaceState(IControlsTethering.STATE_LOCAL_HOTSPOT);
+            sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index eead114..6d64b12 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -129,10 +129,11 @@
                 brightnessMode = mLastBrightnessMode;
             }
 
-            if ((color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS ||
-                    mBrightnessMode != brightnessMode)) {
+            if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
+                    offMS != mOffMS || mBrightnessMode != brightnessMode) {
                 if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
                         + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+                mInitialized = true;
                 mLastColor = mColor;
                 mColor = color;
                 mMode = mode;
@@ -164,6 +165,7 @@
         private int mLastColor;
         private boolean mVrModeEnabled;
         private boolean mUseLowPersistenceForVR;
+        private boolean mInitialized;
     }
 
     public LightsService(Context context) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4c58ffd..f97a672 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -36,6 +36,7 @@
 import android.media.IAudioService;
 import android.media.IRemoteVolumeController;
 import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.media.session.ISessionManager;
@@ -101,6 +102,7 @@
     private AudioManagerInternal mAudioManagerInternal;
     private ContentResolver mContentResolver;
     private SettingsObserver mSettingsObserver;
+    private ICallback mCallback;
 
     // List of user IDs running in the foreground.
     // Multiple users can be in the foreground if the work profile is on.
@@ -485,6 +487,7 @@
             if (size > 0 && records.get(0).isPlaybackActive(false)) {
                 rememberMediaButtonReceiverLocked(records.get(0));
             }
+            pushAddressedPlayerChangedLocked();
             ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
             for (int i = 0; i < size; i++) {
                 tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
@@ -516,6 +519,52 @@
         }
     }
 
+    private MediaSessionRecord getMediaButtonSessionLocked() {
+        // If we don't have a media button receiver to fall back on
+        // include non-playing sessions for dispatching.
+        boolean useNotPlayingSessions = true;
+        for (int userId : mCurrentUserIdList) {
+            UserRecord ur = mUserRecords.get(userId);
+            if (ur.mLastMediaButtonReceiver != null
+                    || ur.mRestoredMediaButtonReceiver != null) {
+                useNotPlayingSessions = false;
+                break;
+            }
+        }
+        return mPriorityStack.getDefaultMediaButtonSession(
+                mCurrentUserIdList, useNotPlayingSessions);
+    }
+
+    private void pushAddressedPlayerChangedLocked() {
+        if (mCallback == null) {
+            return;
+        }
+        try {
+            MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+            if (mediaButtonSession != null) {
+                mCallback.onAddressedPlayerChangedToMediaSession(
+                        new MediaSession.Token(mediaButtonSession.getControllerBinder()));
+            } else {
+                for (int userId : mCurrentUserIdList) {
+                    UserRecord user = mUserRecords.get(userId);
+                    if (user.mLastMediaButtonReceiver == null
+                            && user.mRestoredMediaButtonReceiver == null) {
+                        continue;
+                    }
+                    ComponentName componentName = user.mLastMediaButtonReceiver != null
+                            ? user.mLastMediaButtonReceiver.getIntent().getComponent()
+                            : user.mRestoredMediaButtonReceiver;
+                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(componentName);
+                    return;
+                }
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
+        }
+    }
+
+    // Remember media button receiver and keep it in the persistent storage.
+    // This should be called whenever there's no media session to receive media button event.
     private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
         PendingIntent receiver = record.getMediaButtonReceiver();
         UserRecord user = mUserRecords.get(record.getUserId());
@@ -530,6 +579,14 @@
         }
     }
 
+    private String getCallingPackageName(int uid) {
+        String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+            if (packages != null && packages.length > 0) {
+                return packages[0];
+            }
+        return "";
+    }
+
     /**
      * Information about a particular user. The contents of this object is
      * guarded by mLock.
@@ -792,12 +849,10 @@
                         Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
                                 + useNotPlayingSessions);
                     }
-                    MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
-                            mCurrentUserIdList, useNotPlayingSessions);
                     if (isVoiceKey(keyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(keyEvent, needWakeLock, session);
+                        handleVoiceKeyEventLocked(keyEvent, needWakeLock);
                     } else {
-                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
+                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
                     }
                 }
             } finally {
@@ -806,6 +861,45 @@
         }
 
         @Override
+        public void setCallback(ICallback callback) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
+                    throw new SecurityException("Only Bluetooth service processes can set"
+                            + " Callback");
+                }
+                synchronized (mLock) {
+                    Log.d(TAG, "Callback + " + mCallback
+                            + " is set by " + getCallingPackageName(uid));
+                    mCallback = callback;
+                    if (mCallback == null) {
+                        return;
+                    }
+                    try {
+                        mCallback.asBinder().linkToDeath(
+                                new IBinder.DeathRecipient() {
+                                    @Override
+                                    public void binderDied() {
+                                        synchronized (mLock) {
+                                            mCallback = null;
+                                        }
+                                    }
+                                }, 0);
+                        pushAddressedPlayerChangedLocked();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to set callback", e);
+                        mCallback = null;
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+
+        @Override
         public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
             final long token = Binder.clearCallingIdentity();
             try {
@@ -932,13 +1026,7 @@
             }
         }
 
-        private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
-                MediaSessionRecord session) {
-            if (session != null && session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
-                // If the phone app has priority just give it the event
-                dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
-                return;
-            }
+        private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
             int action = keyEvent.getAction();
             boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
             if (action == KeyEvent.ACTION_DOWN) {
@@ -955,15 +1043,15 @@
                     if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
                         // Resend the down then send this event through
                         KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
-                        dispatchMediaKeyEventLocked(downEvent, needWakeLock, session);
-                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
+                        dispatchMediaKeyEventLocked(downEvent, needWakeLock);
+                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
                     }
                 }
             }
         }
 
-        private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
-                MediaSessionRecord session) {
+        private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+            MediaSessionRecord session = getMediaButtonSessionLocked();
             if (session != null) {
                 if (DEBUG_MEDIA_KEY_EVENT) {
                     Log.d(TAG, "Sending " + keyEvent + " to " + session);
@@ -977,6 +1065,14 @@
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                         mKeyEventReceiver, Process.SYSTEM_UID,
                         getContext().getPackageName());
+                if (mCallback != null) {
+                    try {
+                        mCallback.onMediaKeyEventDispatchedToMediaSession(keyEvent,
+                                new MediaSession.Token(session.getControllerBinder()));
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to send callback", e);
+                    }
+                }
             } else {
                 // Launch the last PendingIntent we had with priority
                 for (int userId : mCurrentUserIdList) {
@@ -993,26 +1089,41 @@
                     mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
                     try {
                         if (user.mLastMediaButtonReceiver != null) {
+                            PendingIntent receiver = user.mLastMediaButtonReceiver;
                             if (DEBUG_MEDIA_KEY_EVENT) {
                                 Log.d(TAG, "Sending " + keyEvent
-                                        + " to the last known pendingIntent "
-                                        + user.mLastMediaButtonReceiver);
+                                        + " to the last known pendingIntent " + receiver);
                             }
-                            user.mLastMediaButtonReceiver.send(getContext(),
+                            receiver.send(getContext(),
                                     needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                                     mediaButtonIntent, mKeyEventReceiver, mHandler);
+                            if (mCallback != null) {
+                                ComponentName componentName =
+                                        user.mLastMediaButtonReceiver.getIntent().getComponent();
+                                if (componentName != null) {
+                                    mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver(
+                                            keyEvent, componentName);
+                                }
+                            }
                         } else {
+                            ComponentName receiver = user.mRestoredMediaButtonReceiver;
                             if (DEBUG_MEDIA_KEY_EVENT) {
                                 Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
-                                        + user.mRestoredMediaButtonReceiver);
+                                        + receiver);
                             }
-                            mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
+                            mediaButtonIntent.setComponent(receiver);
                             getContext().sendBroadcastAsUser(mediaButtonIntent,
                                     UserHandle.of(userId));
+                            if (mCallback != null) {
+                                mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver(
+                                        keyEvent, receiver);
+                            }
                         }
                     } catch (CanceledException e) {
                         Log.i(TAG, "Error sending key event to media button receiver "
                                 + user.mLastMediaButtonReceiver, e);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to send callback", e);
                     }
                     return;
                 }
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4a8539a..b40a7e5 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -139,7 +139,6 @@
                 " " + mAcceptedEgressIface + "->" + egressIface);
 
         if (egressDisconnected || egressChanged) {
-            clearSourceRulesLocked();
             mAcceptedEgressIface = null;
             mVpn.stopLegacyVpnPrivileged();
         }
@@ -191,24 +190,6 @@
             EventLogTags.writeLockdownVpnConnected(egressType);
             showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
 
-            try {
-                clearSourceRulesLocked();
-
-                mNetService.setFirewallInterfaceRule(iface, true);
-                for (LinkAddress addr : sourceAddrs) {
-                    setFirewallEgressSourceRule(addr, true);
-                }
-
-                mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_ALLOW);
-                mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, Os.getuid(), FIREWALL_RULE_ALLOW);
-
-                mErrorCount = 0;
-                mAcceptedIface = iface;
-                mAcceptedSourceAddr = sourceAddrs;
-            } catch (RemoteException e) {
-                throw new RuntimeException("Problem setting firewall rules", e);
-            }
-
             final NetworkInfo clone = new NetworkInfo(egressInfo);
             augmentNetworkInfo(clone);
             mConnService.sendConnectedBroadcast(clone);
@@ -225,19 +206,11 @@
         Slog.d(TAG, "initLocked()");
 
         mVpn.setEnableTeardown(false);
+        mVpn.setLockdown(true);
 
         final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
         mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, null);
 
-        try {
-            // TODO: support non-standard port numbers
-            mNetService.setFirewallEgressDestRule(mProfile.server, 500, true);
-            mNetService.setFirewallEgressDestRule(mProfile.server, 4500, true);
-            mNetService.setFirewallEgressDestRule(mProfile.server, 1701, true);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Problem setting firewall rules", e);
-        }
-
         handleStateChangedLocked();
     }
 
@@ -254,14 +227,7 @@
         mErrorCount = 0;
 
         mVpn.stopLegacyVpnPrivileged();
-        try {
-            mNetService.setFirewallEgressDestRule(mProfile.server, 500, false);
-            mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false);
-            mNetService.setFirewallEgressDestRule(mProfile.server, 1701, false);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Problem setting firewall rules", e);
-        }
-        clearSourceRulesLocked();
+        mVpn.setLockdown(false);
         hideNotification();
 
         mContext.unregisterReceiver(mResetReceiver);
@@ -278,35 +244,6 @@
         }
     }
 
-    private void clearSourceRulesLocked() {
-        try {
-            if (mAcceptedIface != null) {
-                mNetService.setFirewallInterfaceRule(mAcceptedIface, false);
-                mAcceptedIface = null;
-            }
-            if (mAcceptedSourceAddr != null) {
-                for (LinkAddress addr : mAcceptedSourceAddr) {
-                    setFirewallEgressSourceRule(addr, false);
-                }
-
-                mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_DEFAULT);
-                mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE,Os.getuid(), FIREWALL_RULE_DEFAULT);
-
-                mAcceptedSourceAddr = null;
-            }
-        } catch (RemoteException e) {
-            throw new RuntimeException("Problem setting firewall rules", e);
-        }
-    }
-
-    private void setFirewallEgressSourceRule(
-            LinkAddress address, boolean allow) throws RemoteException {
-        // Our source address based firewall rules must only cover our own source address, not the
-        // whole subnet
-        final String addrString = address.getAddress().getHostAddress();
-        mNetService.setFirewallEgressSourceRule(addrString, allow);
-    }
-
     public void onNetworkInfoChanged() {
         synchronized (mStateLock) {
             handleStateChangedLocked();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 4e14408..d93d620 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -139,7 +139,7 @@
             // (by default is speed-profile) they will be interepreted/JITed. This in itself is
             // not a problem as we will end up doing profile guided compilation. However, some
             // core apps may be loaded by system server which doesn't JIT and we need to make
-            // sure we don't interpret-only
+            // sure we are not interpreting all their code in that process.
             int compilationReason = p.coreApp
                     ? PackageManagerService.REASON_CORE_APP
                     : PackageManagerService.REASON_AB_OTA;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index d9ea728..71eb137 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -150,10 +150,14 @@
 
         // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
         // paths (b/34169257).
-        final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+        String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+        // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
         final int dexoptFlags = getDexFlags(pkg, compilerFilter);
 
         int result = DEX_OPT_SKIPPED;
+        // TODO: Iterate based on dependency hierarchy (currently alphabetically by name)
+        // (b/37480811).
+        String basePathCheck = null;
         for (String path : paths) {
             for (String dexCodeIsa : dexCodeInstructionSets) {
                 int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
@@ -165,6 +169,22 @@
                 if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
                     result = newResult;
                 }
+                // Add the relative path of code we just compiled to the shared libraries.
+                int slashIndex = path.lastIndexOf('/') + 1;
+                String relativePath = path.substring(slashIndex);
+                if (sharedLibrariesPath == null) {
+                    sharedLibrariesPath = relativePath;
+                } else {
+                    sharedLibrariesPath += ":" + relativePath;
+                }
+                // Sanity check that the base paths are all the same.
+                String basePath = path.substring(0, slashIndex);
+                if (basePathCheck == null) {
+                    basePathCheck = basePath;
+                } else if (!basePath.equals(basePathCheck)) {
+                    Slog.wtf(TAG, "Split paths have different base paths: " + basePath + " and " +
+                        basePathCheck);
+                }
             }
         }
         return result;
@@ -340,10 +360,10 @@
         boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
         if (vmSafeMode) {
             // For the compilation, it doesn't really matter what we return here because installd
-            // will replace the filter with interpret-only anyway.
+            // will replace the filter with 'quicken' anyway.
             // However, we return a non profile guided filter so that we simplify the logic of
             // merging profiles.
-            // TODO(calin): safe mode path could be simplified if we pass interpret-only from
+            // TODO(calin): safe mode path could be simplified if we pass 'quicken' from
             //              here rather than letting installd decide on the filter.
             return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
         }
@@ -529,9 +549,13 @@
 
         @Override
         protected int adjustDexoptNeeded(int dexoptNeeded) {
-            // Ensure compilation, no matter the current state.
-            // TODO: The return value is wrong when patchoat is needed.
-            return DexFile.DEX2OAT_FROM_SCRATCH;
+            if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+                // Ensure compilation by pretending a compiler filter change on the
+                // apk/odex location (the reason for the '-'. A positive value means
+                // the 'oat' location).
+                return -DexFile.DEX2OAT_FOR_FILTER;
+            }
+            return dexoptNeeded;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b207b81..3196b09 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7364,20 +7364,7 @@
             // are verify-profile but for preopted apps there's no profile.
             // Do a hacky check to ensure that if we have no profiles (a reasonable indication
             // that before the OTA the app was preopted) the app gets compiled with a non-profile
-            // filter (by default interpret-only).
-            // Note that at this stage unused apps are already filtered.
-            if (isSystemApp(pkg) &&
-                    DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
-                    !Environment.getReferenceProfile(pkg.packageName).exists()) {
-                compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
-            }
-
-            // If the OTA updates a system app which was previously preopted to a non-preopted state
-            // the app might end up being verified at runtime. That's because by default the apps
-            // are verify-profile but for preopted apps there's no profile.
-            // Do a hacky check to ensure that if we have no profiles (a reasonable indication
-            // that before the OTA the app was preopted) the app gets compiled with a non-profile
-            // filter (by default interpret-only).
+            // filter (by default 'quicken').
             // Note that at this stage unused apps are already filtered.
             if (isSystemApp(pkg) &&
                     DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1bfc157..2f000c2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1454,10 +1454,10 @@
         pw.println("      -f: force compilation even if not needed");
         pw.println("      -m: select compilation mode");
         pw.println("          MODE is one of the dex2oat compiler filters:");
-        pw.println("            verify-none");
-        pw.println("            verify-at-runtime");
-        pw.println("            verify-profile");
-        pw.println("            interpret-only");
+        pw.println("            assume-verified");
+        pw.println("            extract");
+        pw.println("            verify");
+        pw.println("            quicken");
         pw.println("            space-profile");
         pw.println("            space");
         pw.println("            speed-profile");
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
index b0e0230..703b415 100644
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -46,7 +46,7 @@
     }
 
     public String toString() {
-        return String.format("%s{version: %d, maxSize: %d format: %d}", getClass().getSimpleName(),
+        return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
                 apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
     }
 }
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 0a90749..985a12c 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -18,6 +18,14 @@
 
 import static android.system.OsConstants.*;
 
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.internal.util.BitUtils.getUint16;
+import static com.android.internal.util.BitUtils.getUint32;
+import static com.android.internal.util.BitUtils.getUint8;
+import static com.android.internal.util.BitUtils.uint16;
+import static com.android.internal.util.BitUtils.uint32;
+import static com.android.internal.util.BitUtils.uint8;
+
 import android.os.SystemClock;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -1157,41 +1165,9 @@
         }
     }
 
-    private static int uint8(byte b) {
-        return b & 0xff;
-    }
-
-    private static int uint16(short s) {
-        return s & 0xffff;
-    }
-
-    private static long uint32(int i) {
-        return i & 0xffffffffL;
-    }
-
-    private static int getUint8(ByteBuffer buffer, int position) {
-        return uint8(buffer.get(position));
-    }
-
-    private static int getUint16(ByteBuffer buffer, int position) {
-        return uint16(buffer.getShort(position));
-    }
-
-    private static long getUint32(ByteBuffer buffer, int position) {
-        return uint32(buffer.getInt(position));
-    }
-
     // TODO: move to android.net.NetworkUtils
     @VisibleForTesting
     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
-        return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
-    }
-
-    @VisibleForTesting
-    public static int bytesToInt(byte[] addrBytes) {
-        return (uint8(addrBytes[0]) << 24)
-                + (uint8(addrBytes[1]) << 16)
-                + (uint8(addrBytes[2]) << 8)
-                + (uint8(addrBytes[3]));
+        return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
     }
 }
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 745764b..6608167 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -524,7 +524,7 @@
         try {
             mNwService.registerObserver(mNetlinkTracker);
         } catch (RemoteException e) {
-            Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
+            logError("Couldn't register NetlinkTracker: %s", e);
         }
 
         mMultinetworkPolicyTracker.start();
@@ -611,19 +611,36 @@
             return;
         }
 
+        // Thread-unsafe access to mApfFilter but just used for debugging.
+        final ApfFilter apfFilter = mApfFilter;
+        final ProvisioningConfiguration provisioningConfig = mConfiguration;
+        final ApfCapabilities apfCapabilities = (provisioningConfig != null)
+                ? provisioningConfig.mApfCapabilities : null;
+
         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
         pw.println(mTag + " APF dump:");
         pw.increaseIndent();
-        // Thread-unsafe access to mApfFilter but just used for debugging.
-        ApfFilter apfFilter = mApfFilter;
         if (apfFilter != null) {
             apfFilter.dump(pw);
         } else {
-            pw.println("No apf support");
+            pw.print("No active ApfFilter; ");
+            if (provisioningConfig == null) {
+                pw.println("IpManager not yet started.");
+            } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
+                pw.println("Hardware does not support APF.");
+            } else {
+                pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
+            }
         }
         pw.decreaseIndent();
 
         pw.println();
+        pw.println(mTag + " current ProvisioningConfiguration:");
+        pw.increaseIndent();
+        pw.println(Objects.toString(provisioningConfig, "N/A"));
+        pw.decreaseIndent();
+
+        pw.println();
         pw.println(mTag + " StateMachine dump:");
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
@@ -684,7 +701,9 @@
 
     // TODO: Migrate all Log.e(...) to logError(...).
     private void logError(String fmt, Object... args) {
-        mLocalLog.log("ERROR " + String.format(fmt, args));
+        final String msg = "ERROR " + String.format(fmt, args);
+        Log.e(mTag, msg);
+        mLocalLog.log(msg);
     }
 
     private void getNetworkInterface() {
@@ -692,7 +711,7 @@
             mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
         } catch (SocketException | NullPointerException e) {
             // TODO: throw new IllegalStateException.
-            Log.e(mTag, "ALERT: Failed to get interface object: ", e);
+            logError("Failed to get interface object: %s", e);
         }
     }
 
@@ -948,7 +967,7 @@
             ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
             mNwService.setInterfaceConfig(mInterfaceName, ifcg);
         } catch (IllegalStateException | RemoteException e) {
-            Log.e(mTag, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
+            logError("Failed to clear IPv4 address on interface %s: %s", mInterfaceName, e);
         }
     }
 
@@ -1074,13 +1093,13 @@
         try {
             mNwService.disableIpv6(mInterfaceName);
         } catch (Exception e) {
-            Log.e(mTag, "Failed to disable IPv6" + e);
+            logError("Failed to disable IPv6: %s", e);
         }
 
         try {
             mNwService.clearInterfaceAddresses(mInterfaceName);
         } catch (Exception e) {
-            Log.e(mTag, "Failed to clear addresses " + e);
+            logError("Failed to clear addresses: %s", e);
         }
     }
 
@@ -1404,7 +1423,7 @@
                     if (setIPv4Address(ipAddress)) {
                         mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
                     } else {
-                        Log.e(mTag, "Failed to set IPv4 address!");
+                        logError("Failed to set IPv4 address.");
                         dispatchCallback(ProvisioningChange.LOST_PROVISIONING,
                                 new LinkProperties(mLinkProperties));
                         transitionTo(mStoppingState);
diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java
index 5b068c0..dae93af 100644
--- a/services/net/java/android/net/util/ConnectivityPacketSummary.java
+++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java
@@ -368,9 +368,9 @@
 
         byte[] bytes = new byte[ETHER_ADDR_LEN];
         mac.get(bytes, 0, bytes.length);
-        Byte[] printableBytes = new Byte[bytes.length];
+        Object[] printableBytes = new Object[bytes.length];
         int i = 0;
-        for (byte b : bytes) printableBytes[i++] = b;
+        for (byte b : bytes) printableBytes[i++] = new Byte(b);
 
         final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x";
         return String.format(MAC48_FORMAT, printableBytes);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 9822936..239cdcf 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -878,6 +878,7 @@
      * {@link Call#sendRttRequest()}
      */
     public static final class RttModifyStatus {
+        private RttModifyStatus() {}
         /**
          * Session modify request was successful.
          */
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index c42a835..5530cb7 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -43,6 +43,15 @@
 
     /**
      * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
+     * sort order for {@link PhoneAccount}s from the same
+     * {@link android.telecom.ConnectionService}.
+     * @hide
+     */
+    public static final String EXTRA_SORT_ORDER =
+            "android.telecom.extra.SORT_ORDER";
+
+    /**
+     * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
      * maximum permitted length of a call subject specified via the
      * {@link TelecomManager#EXTRA_CALL_SUBJECT} extra on an
      * {@link android.content.Intent#ACTION_CALL} intent.  Ultimately a {@link ConnectionService} is
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7e0fbb9..e1239d0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -604,6 +604,38 @@
         "vvm_cellular_data_required_bool";
 
     /**
+     * The default OMTP visual voicemail client prefix to use. Defaulted to "//VVM"
+     */
+    public static final String KEY_VVM_CLIENT_PREFIX_STRING =
+            "vvm_client_prefix_string";
+
+    /**
+     * Whether to use SSL to connect to the visual voicemail IMAP server. Defaulted to false.
+     */
+    public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
+
+    /**
+     * A set of capabilities that should not be used even if it is reported by the visual voicemail
+     * IMAP CAPABILITY command.
+     */
+    public static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
+            "vvm_disabled_capabilities_string_array";
+
+    /**
+     * Whether legacy mode should be used when the visual voicemail client is disabled.
+     *
+     * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on
+     * the client side all network operations are disabled. SMSs are still monitored so a new
+     * message SYNC SMS will be translated to show a message waiting indicator, like traditional
+     * voicemails.
+     *
+     * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to
+     * function without the data cost.
+     */
+    public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL =
+            "vvm_legacy_mode_enabled_bool";
+
+    /**
      * Whether to prefetch audio data on new voicemail arrival, defaulted to true.
      */
     public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
@@ -611,10 +643,20 @@
     /**
      * The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
      * and carrier visual voicemail are not active at the same time.
+     *
+     * @deprecated use {@link #KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}.
      */
+    @Deprecated
     public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
 
     /**
+     * A list of the carrier's visual voicemail app package names to ensure that dialer visual
+     * voicemail and carrier visual voicemail are not active at the same time.
+     */
+    public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
+            "carrier_vvm_package_name_string_array";
+
+    /**
      * Flag specifying whether ICCID is showed in SIM Status screen, default to false.
      */
     public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -838,6 +880,12 @@
     public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
             "stk_disable_launch_browser_bool";
 
+    /**
+     * Boolean indicating if show data RAT icon on status bar even when data is disabled
+     * @hide
+     */
+    public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL =
+            "always_show_data_rat_icon_bool";
 
     // These variables are used by the MMS service and exposed through another API, {@link
     // SmsManager}. The variable names and string values are copied from there.
@@ -936,6 +984,20 @@
             "carrier_default_actions_on_dcfailure_string_array";
 
     /**
+     * Defines carrier-specific actions which act upon
+     * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the
+     * default carrier app
+     * Format: "CARRIER_ACTION_IDX, ..."
+     * Where {@code CARRIER_ACTION_IDX} is an integer defined in
+     * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+     * Example:
+     * {@link com.android.carrierdefaultapp.CarrierActionUtils
+     * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset}
+     * @hide
+     */
+    public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET =
+            "carrier_default_actions_on_reset_string_array";
+    /**
      * Defines a list of acceptable redirection url for default carrier app
      * @hides
      */
@@ -1338,8 +1400,13 @@
         sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
         sDefaults.putString(KEY_VVM_TYPE_STRING, "");
         sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
+        sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING,"//VVM");
+        sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL,false);
+        sDefaults.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL,false);
         sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true);
         sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
+        sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
@@ -1451,7 +1518,8 @@
         sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
                 new String[]{
                         "com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
-                                "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
+                                "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED," +
+                                "com.android.internal.telephony.CARRIER_SIGNAL_RESET"
                 });
         sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
 
@@ -1462,6 +1530,9 @@
                         //4: CARRIER_ACTION_DISABLE_METERED_APNS
                         //1: CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
                 });
+        sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET, new String[]{
+                "6" //6: CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS
+                });
         sDefaults.putStringArray(KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY, null);
 
         // Rat families: {GPRS, EDGE}, {EVDO, EVDO_A, EVDO_B}, {UMTS, HSPA, HSDPA, HSUPA, HSPAP},
@@ -1491,6 +1562,7 @@
         sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
         sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
+        sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
new file mode 100644
index 0000000..862c919
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.mbms.DownloadCallback;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsInitializationException;
+import android.telephony.mbms.vendor.IMbmsDownloadService;
+import android.util.Log;
+
+import java.util.List;
+
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+/** @hide */
+public class MbmsDownloadManager {
+    private static final String LOG_TAG = MbmsDownloadManager.class.getSimpleName();
+
+    /**
+     * The MBMS middleware should send this when a download of single file has completed or
+     * failed. Mandatory extras are
+     * {@link #EXTRA_RESULT}
+     * {@link #EXTRA_INFO}
+     * {@link #EXTRA_REQUEST}
+     * {@link #EXTRA_TEMP_LIST}
+     * {@link #EXTRA_FINAL_URI}
+     *
+     * TODO: future systemapi
+     */
+    public static final String ACTION_DOWNLOAD_RESULT_INTERNAL =
+            "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
+
+    /**
+     * The MBMS middleware should send this when it wishes to request {@code content://} URIs to
+     * serve as temp files for downloads or when it wishes to resume paused downloads. Mandatory
+     * extras are
+     * {@link #EXTRA_REQUEST}
+     *
+     * Optional extras are
+     * {@link #EXTRA_FD_COUNT} (0 if not present)
+     * {@link #EXTRA_PAUSED_LIST} (empty if not present)
+     *
+     * TODO: future systemapi
+     */
+    public static final String ACTION_FILE_DESCRIPTOR_REQUEST =
+            "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
+
+    /**
+     * The MBMS middleware should send this when it wishes to clean up temp  files in the app's
+     * filesystem. Mandatory extras are:
+     * {@link #EXTRA_TEMP_FILES_IN_USE}
+     *
+     * TODO: future systemapi
+     */
+    public static final String ACTION_CLEANUP =
+            "android.telephony.mbms.action.CLEANUP";
+
+    /**
+     * Integer extra indicating the result code of the download.
+     * TODO: put in link to error list
+     * TODO: future systemapi (here and and all extras)
+     */
+    public static final String EXTRA_RESULT = "android.telephony.mbms.extra.RESULT";
+
+    /**
+     * Extra containing the {@link android.telephony.mbms.FileInfo} for which the download result
+     * is for. Must not be null.
+     */
+    public static final String EXTRA_INFO = "android.telephony.mbms.extra.INFO";
+
+    /**
+     * Extra containing the {@link DownloadRequest} for which the download result or file
+     * descriptor request is for. Must not be null.
+     */
+    public static final String EXTRA_REQUEST = "android.telephony.mbms.extra.REQUEST";
+
+    /**
+     * Extra containing a {@link List} of {@link Uri}s that were used as temp files for this
+     * completed file. These {@link Uri}s should have scheme {@code file://}, and the temp
+     * files will be deleted upon receipt of the intent.
+     * May be null.
+     */
+    public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
+
+    /**
+     * Extra containing a single {@link Uri} indicating the path to the temp file in which the
+     * decoded downloaded file resides. Must not be null.
+     */
+    public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
+
+    /**
+     * Extra containing an integer indicating the number of temp files requested.
+     */
+    public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
+
+    /**
+     * Extra containing a list of {@link Uri}s that the middleware is requesting access to via
+     * {@link #ACTION_FILE_DESCRIPTOR_REQUEST} in order to resume downloading. These {@link Uri}s
+     * should have scheme {@code file://}.
+     */
+    public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
+
+    /**
+     * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the
+     * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These are temp files that are meant
+     * to be used for new file downloads.
+     */
+    public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
+
+    /**
+     * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the
+     * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These
+     * {@link android.telephony.mbms.UriPathPair}s contain {@code content://} URIs that provide
+     * access to previously paused downloads.
+     */
+    public static final String EXTRA_PAUSED_URI_LIST =
+            "android.telephony.mbms.extra.PAUSED_URI_LIST";
+
+    /**
+     * Extra containing a list of {@link Uri}s indicating temp files which the middleware is
+     * still using.
+     */
+    public static final String EXTRA_TEMP_FILES_IN_USE =
+            "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
+
+    public static final int RESULT_SUCCESSFUL = 1;
+    public static final int RESULT_CANCELLED  = 2;
+    public static final int RESULT_EXPIRED    = 3;
+    // TODO - more results!
+
+    private final Context mContext;
+    private int mSubId = INVALID_SUBSCRIPTION_ID;
+
+    private IMbmsDownloadService mService;
+    private final IMbmsDownloadManagerCallback mCallback;
+    private final String mDownloadAppName;
+
+    private MbmsDownloadManager(Context context, IMbmsDownloadManagerCallback callback,
+            String downloadAppName, int subId) {
+        mContext = context;
+        mCallback = callback;
+        mDownloadAppName = downloadAppName;
+        mSubId = subId;
+    }
+
+    /**
+     * Create a new MbmsDownloadManager using the system default data subscription ID.
+     *
+     * Note that this call will bind a remote service and that may take a bit.  This
+     * may throw an Illegal ArgumentException or RemoteException.
+     *
+     * @hide
+     */
+    public static MbmsDownloadManager createManager(Context context,
+            IMbmsDownloadManagerCallback listener, String downloadAppName)
+            throws MbmsInitializationException{
+        MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
+                SubscriptionManager.getDefaultSubscriptionId());
+        mdm.bindAndInitialize();
+        return mdm;
+    }
+
+    /**
+     * Create a new MbmsDownloadManager using the given subscription ID.
+     *
+     * Note that this call will bind a remote service and that may take a bit.  This
+     * may throw an Illegal ArgumentException or RemoteException.
+     *
+     * @hide
+     */
+
+    public static MbmsDownloadManager createManager(Context context,
+            IMbmsDownloadManagerCallback listener, String downloadAppName, int subId)
+            throws MbmsInitializationException {
+        MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
+                subId);
+        mdm.bindAndInitialize();
+        return mdm;
+    }
+
+    private void bindAndInitialize() throws MbmsInitializationException {
+        // TODO: bind
+        try {
+            mService.initialize(mDownloadAppName, mSubId, mCallback);
+        } catch (RemoteException e) {
+            throw new MbmsInitializationException(0); // TODO: proper error code
+        }
+    }
+
+    /**
+     * Gets the list of files published for download.
+     * They may occur at times far in the future.
+     * servicesClasses lets the app filter on types of files and is opaque data between
+     *     the app and the carrier
+     *
+     * Multiple calls replace trhe list of serviceClasses of interest.
+     *
+     * May throw an IllegalArgumentException or RemoteException.
+     *
+     * Synchronous responses include
+     * <li>SUCCESS</li>
+     * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+     *
+     * Asynchronous errors through the listener include any of the errors except
+     * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
+     * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+     * <li>ERROR_MSDC_END_OF_SESSION</li>
+     */
+    public int getFileServices(List<String> serviceClasses) {
+        return 0;
+    }
+
+
+    /**
+     * Requests a future download.
+     * returns a token which may be used to cancel a download.
+     * downloadListener is an optional callback object which can be used to get progress reports
+     *     of a currently occuring download.  Note this can only run while the calling app
+     *     is running, so future downloads will simply result in resultIntents being sent
+     *     for completed or errored-out downloads.  A NULL indicates no callbacks are needed.
+     *
+     * May throw an IllegalArgumentException or RemoteExcpetion.
+     *
+     * Asynchronous errors through the listener include any of the errors
+     */
+    public DownloadRequest download(DownloadRequest downloadRequest, DownloadCallback listener) {
+        return null;
+    }
+
+    /**
+     * Returns a list DownloadRequests that originated from this application (UID).
+     *
+     * May throw a RemoteException.
+     *
+     * Asynchronous errors through the listener include any of the errors except
+     * <li>ERROR_UNABLED_TO_START_SERVICE</li>
+     * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+     * <li>ERROR_MSDC_END_OF_SESSION</li>
+     */
+    public List<DownloadRequest> listPendingDownloads() {
+        return null;
+    }
+
+    /**
+     * Attempts to cancel the specified DownloadRequest.
+     *
+     * May throw a RemoteException.
+     *
+     * Synchronous responses may include
+     * <li>SUCCESS</li>
+     * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+     * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+     */
+    public int cancelDownload(DownloadRequest downloadRequest) {
+        return 0;
+    }
+
+    /**
+     * Gets information about current and known upcoming downloads.
+     *
+     * Current is a straightforward count of the files being downloaded "now"
+     * for some definition of now (may be racey).
+     * Future downloads include counts of files with pending repair operations, counts of
+     * files with future downloads and indication of scheduled download times with unknown
+     * file details.
+     *
+     * May throw an IllegalArgumentException or RemoteException.
+     *
+     * If the DownloadRequest is unknown the results will be null.
+     */
+    public DownloadStatus getDownloadStatus(DownloadRequest downloadRequest) {
+        return null;
+    }
+
+    /**
+     * Resets middleware knowledge regarding this download request.
+     *
+     * This state consists of knowledge of what files have already been downloaded.
+     * Normally the middleware won't download files who's hash matches previously downloaded
+     * content, even if that content has since been deleted.  If this function is called
+     * repeated content will be downloaded again when available.  This does not interrupt
+     * in-progress downloads.
+     *
+     * May throw an IllegalArgumentException or RemoteException.
+     *
+     * <li>SUCCESS</li>
+     * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+     * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+     */
+    public int resetDownloadKnowledge(DownloadRequest downloadRequest) {
+        return 0;
+    }
+
+    public void dispose() {
+        try {
+            if (mService != null) {
+                mService.dispose(mDownloadAppName, mSubId);
+            } else {
+                Log.i(LOG_TAG, "Service already dead");
+            }
+        } catch (RemoteException e) {
+            // Ignore
+            Log.i(LOG_TAG, "Remote exception while disposing of service");
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
new file mode 100644
index 0000000..770a04a
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IStreamingServiceCallback;
+import android.telephony.mbms.MbmsInitializationException;
+import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.StreamingServiceInfo;
+import android.telephony.mbms.vendor.IMbmsStreamingService;
+import android.util.Log;
+
+import java.util.List;
+
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+/** @hide */
+public class MbmsStreamingManager {
+    private static final String LOG_TAG = "MbmsStreamingManager";
+    private static final boolean DEBUG = true;
+    private IMbmsStreamingService mService;
+    private IMbmsStreamingManagerCallback mCallbackToApp;
+    private final String mAppName;
+
+    private final Context mContext;
+    private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
+
+    /** @hide */
+    private MbmsStreamingManager(Context context, IMbmsStreamingManagerCallback listener,
+                    String streamingAppName, int subscriptionId) {
+        mContext = context;
+        mAppName = streamingAppName;
+        mCallbackToApp = listener;
+        mSubscriptionId = subscriptionId;
+    }
+
+    /**
+     * Create a new MbmsStreamingManager using the given subscription ID.
+     *
+     * Note that this call will bind a remote service and that may take a bit.  This
+     * may throw an IllegalArgumentException or RemoteException.
+     * TODO: document this and add exceptions that can be thrown for synchronous
+     * initialization/bind errors
+     *
+     * @param context
+     * @param listener
+     * @param streamingAppName
+     * @param subscriptionId
+     * @return
+     */
+    public static MbmsStreamingManager create(Context context,
+            IMbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
+            throws MbmsInitializationException {
+        MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
+                streamingAppName, subscriptionId);
+        manager.bindAndInitialize();
+        return manager;
+    }
+
+    /**
+     * Create a new MbmsStreamingManager using the system default data subscription ID.
+     *
+     * Note that this call will bind a remote service and that may take a bit.  This
+     * may throw an IllegalArgumentException or RemoteException.
+     */
+    public static MbmsStreamingManager create(Context context,
+            IMbmsStreamingManagerCallback listener, String streamingAppName)
+            throws MbmsInitializationException {
+        // TODO: get default sub id
+        int subId = INVALID_SUBSCRIPTION_ID;
+        MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
+                streamingAppName, subId);
+        manager.bindAndInitialize();
+        return manager;
+    }
+
+    /**
+     * Terminates this instance, ending calls to the registered listener.  Also terminates
+     * any streaming services spawned from this instance.
+     */
+    public void dispose() {
+        // service.dispose(streamingAppName);
+    }
+
+    /**
+     * An inspection API to retrieve the list of streaming media currently be advertised.
+     * The results are returned asynchronously through the previously registered callback.
+     * serviceClasses lets the app filter on types of programming and is opaque data between
+     * the app and the carrier.
+     *
+     * Multiple calls replace the list of serviceClasses of interest.
+     *
+     * May throw an IllegalArgumentException or RemoteException.
+     *
+     * Synchronous responses include
+     * <li>SUCCESS</li>
+     * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+     *
+     * Asynchronous errors through the listener include any of the errors except
+     * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
+     * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+     * <li>ERROR_MSDC_END_OF_SESSION</li>
+     */
+    public int getStreamingServices(List<String> classList) {
+        return 0;
+    }
+
+    /**
+     * Starts streaming a requested service, reporting status to the indicated listener.
+     * Returns an object used to control that stream.
+     *
+     * May throw an IllegalArgumentException or RemoteException.
+     *
+     * Asynchronous errors through the listener include any of the errors
+     */
+    public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
+            IStreamingServiceCallback listener) {
+        return null;
+    }
+
+    /**
+     * Lists all the services currently being streamed to the device by this application
+     * on this given subId.  Results are returned asynchronously through the previously
+     * registered callback.
+     *
+     * May throw a RemoteException.
+     *
+     * The return value is a success/error-code with the following possible values:
+     * <li>SUCCESS</li>
+     * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+     *
+     * Asynchronous errors through the listener include any of the errors except
+     * <li>ERROR_UNABLED_TO_START_SERVICE</li>
+     * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+     * <li>ERROR_MSDC_END_OF_SESSION</li>
+     *
+     */
+    public int getActiveStreamingServices() {
+        return 0;
+    }
+
+    private void logd(String str) {
+        Log.d(LOG_TAG, str);
+    }
+
+    private boolean isServiceConnected() {
+        return mService != null;
+    }
+
+    private void bindAndInitialize() throws MbmsInitializationException {
+        // TODO: bind to the service
+        try {
+            int returnCode = mService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
+            if (returnCode != 0) {
+                throw new MbmsInitializationException(returnCode);
+            }
+        } catch (RemoteException e) {
+            throw new MbmsInitializationException(/* some error */ 0);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 675b902..5985813 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,24 +16,32 @@
 
 package android.telephony;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.WorkerThread;
+import android.annotation.SystemApi;
 import android.app.ActivityThread;
+import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.os.BatteryStats;
-import android.os.ResultReceiver;
+import android.os.Binder;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.service.carrier.CarrierIdentifier;
@@ -61,6 +69,7 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -838,6 +847,29 @@
      */
     public static final String VVM_TYPE_CVVM = "vvm_type_cvvm";
 
+    /**
+     * @hide
+     */
+    public static final String USSD_RESPONSE = "USSD_RESPONSE";
+
+    /**
+     * USSD return code success.
+     * @hide
+     */
+    public static final int USSD_RETURN_SUCCESS = 100;
+
+    /**
+     * USSD return code for failure case.
+     * @hide
+     */
+    public static final int USSD_RETURN_FAILURE = -1;
+
+    /**
+     * USSD return code for failure case.
+     * @hide
+     */
+    public static final int USSD_ERROR_SERVICE_UNAVAIL = -2;
+
     //
     //
     // Device Info
@@ -853,7 +885,7 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getDeviceSoftwareVersion() {
-        return getDeviceSoftwareVersion(getDefaultSim());
+        return getDeviceSoftwareVersion(getSlotIndex());
     }
 
     /**
@@ -939,7 +971,7 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getImei() {
-        return getImei(getDefaultSim());
+        return getImei(getSlotIndex());
     }
 
     /**
@@ -971,7 +1003,7 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
     public String getMeid() {
-        return getMeid(getDefaultSim());
+        return getMeid(getSlotIndex());
     }
 
     /**
@@ -1001,7 +1033,7 @@
      */
     /** {@hide}*/
     public String getNai() {
-        return getNai(getDefaultSim());
+        return getNai(getSlotIndex());
     }
 
     /**
@@ -1245,7 +1277,7 @@
     }
 
     private int getPhoneTypeFromProperty() {
-        return getPhoneTypeFromProperty(getDefaultPhone());
+        return getPhoneTypeFromProperty(getPhoneId());
     }
 
     /** {@hide} */
@@ -1259,7 +1291,7 @@
     }
 
     private int getPhoneTypeFromNetworkType() {
-        return getPhoneTypeFromNetworkType(getDefaultPhone());
+        return getPhoneTypeFromNetworkType(getPhoneId());
     }
 
     /** {@hide} */
@@ -1442,7 +1474,7 @@
      * on a CDMA network).
      */
     public String getNetworkOperator() {
-        return getNetworkOperatorForPhone(getDefaultPhone());
+        return getNetworkOperatorForPhone(getPhoneId());
     }
 
     /**
@@ -1478,18 +1510,23 @@
 
 
     /**
-     * Returns the network specifier of the subscription ID pinned to the TelephonyManager.
+     * Returns the network specifier of the subscription ID pinned to the TelephonyManager. The
+     * network specifier is used by {@link
+     * android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to create a {@link
+     * android.net.NetworkRequest} that connects through the subscription.
      *
      * @see android.net.NetworkRequest.Builder#setNetworkSpecifier(String)
      * @see #createForSubscriptionId(int)
      * @see #createForPhoneAccountHandle(PhoneAccountHandle)
      */
     public String getNetworkSpecifier() {
-        return String.valueOf(mSubId);
+        return String.valueOf(getSubId());
     }
 
     /**
-     * Returns the carrier config of the subscription ID pinned to the TelephonyManager.
+     * Returns the carrier config of the subscription ID pinned to the TelephonyManager. If an
+     * invalid subscription ID is pinned to the TelephonyManager, the returned config will contain
+     * default values.
      *
      * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
      * READ_PHONE_STATE}
@@ -1498,10 +1535,11 @@
      * @see #createForSubscriptionId(int)
      * @see #createForPhoneAccountHandle(PhoneAccountHandle)
      */
+    @WorkerThread
     public PersistableBundle getCarrierConfig() {
         CarrierConfigManager carrierConfigManager = mContext
                 .getSystemService(CarrierConfigManager.class);
-        return carrierConfigManager.getConfigForSubId(mSubId);
+        return carrierConfigManager.getConfigForSubId(getSubId());
     }
 
     /**
@@ -1538,7 +1576,7 @@
      * on a CDMA network).
      */
     public String getNetworkCountryIso() {
-        return getNetworkCountryIsoForPhone(getDefaultPhone());
+        return getNetworkCountryIsoForPhone(getPhoneId());
     }
 
     /**
@@ -1684,6 +1722,9 @@
      * Returns a constant indicating the radio technology (network type)
      * currently in use on the device for data transmission.
      *
+     * If this object has been created with {@link #createForSubscriptionId}, applies to the given
+     * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -1708,7 +1749,7 @@
      * @see #NETWORK_TYPE_HSPAP
      */
     public int getDataNetworkType() {
-        return getDataNetworkType(getSubId());
+        return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
     }
 
     /**
@@ -1932,7 +1973,7 @@
      * @return true if a ICC card is present
      */
     public boolean hasIccCard() {
-        return hasIccCard(getDefaultSim());
+        return hasIccCard(getSlotIndex());
     }
 
     /**
@@ -1973,7 +2014,7 @@
      * @see #SIM_STATE_CARD_RESTRICTED
      */
     public int getSimState() {
-        int slotIndex = getDefaultSim();
+        int slotIndex = getSlotIndex();
         // slotIndex may be invalid due to sim being absent. In that case query all slots to get
         // sim state
         if (slotIndex < 0) {
@@ -2102,7 +2143,7 @@
      * @see #getSimState
      */
     public String getSimOperatorName() {
-        return getSimOperatorNameForPhone(getDefaultPhone());
+        return getSimOperatorNameForPhone(getPhoneId());
     }
 
     /**
@@ -2134,7 +2175,7 @@
      * Returns the ISO country code equivalent for the SIM provider's country code.
      */
     public String getSimCountryIso() {
-        return getSimCountryIsoForPhone(getDefaultPhone());
+        return getSimCountryIsoForPhone(getPhoneId());
     }
 
     /**
@@ -2682,6 +2723,33 @@
         return false;
     }
 
+
+    /**
+     * Returns the package responsible of processing visual voicemail for the subscription ID pinned
+     * to the TelephonyManager. Returns {@code null} when there is no package responsible for
+     * processing visual voicemail for the subscription.
+     *
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+     * READ_PHONE_STATE}
+     *
+     * @see #createForSubscriptionId(int)
+     * @see #createForPhoneAccountHandle(PhoneAccountHandle)
+     * @see VisualVoicemailService
+     */
+    @Nullable
+    public String getVisualVoicemailPackageName() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony
+                        .getVisualVoicemailPackageName(mContext.getOpPackageName(), getSubId());
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
     /**
      * Enables the visual voicemail SMS filter for a phone account. When the filter is
      * enabled, Incoming SMS messages matching the OMTP VVM SMS interface will be redirected to the
@@ -2758,18 +2826,17 @@
 
     /**
      * @returns the settings of the visual voicemail SMS filter for a phone account set by the
-     * package, or {@code null} if the filter is disabled.
+     * current active visual voicemail client, or {@code null} if the filter is disabled.
      *
      * <p>Requires the calling app to have READ_PRIVILEGED_PHONE_STATE permission.
      */
     /** @hide */
     @Nullable
-    public VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(String packageName,
-            int subId) {
+    public VisualVoicemailSmsFilterSettings getActiveVisualVoicemailSmsFilterSettings(int subId) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getSystemVisualVoicemailSmsFilterSettings(packageName, subId);
+                return telephony.getActiveVisualVoicemailSmsFilterSettings(subId);
             }
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -2779,6 +2846,35 @@
     }
 
     /**
+     * Send a visual voicemail SMS. The IPC caller must be the current default dialer.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SEND_SMS SEND_SMS}
+     *
+     * @param phoneAccountHandle The account to send the SMS with.
+     * @param number The destination number.
+     * @param port The destination port for data SMS, or 0 for text SMS.
+     * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream.
+     * @param sentIntent The sent intent passed to the {@link SmsManager}
+     *
+     * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
+     * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
+     *
+     * @hide
+     */
+    public void sendVisualVoicemailSmsForSubscriber(int subId, String number, int port,
+            String text, PendingIntent sentIntent) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.sendVisualVoicemailSmsForSubscriber(
+                        mContext.getOpPackageName(), subId, number, port, text, sentIntent);
+            }
+        } catch (RemoteException ex) {
+        }
+    }
+
+    /**
      * Initial SIM activation state, unknown. Not set by any carrier apps.
      * @hide
      */
@@ -3924,35 +4020,67 @@
      * subId is returned. Otherwise, the default subId will be returned.
      */
     private int getSubId() {
-      if (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
-        return getDefaultSubscription();
+      if (SubscriptionManager.isUsableSubIdValue(mSubId)) {
+        return mSubId;
       }
-      return mSubId;
+      return SubscriptionManager.getDefaultSubscriptionId();
     }
 
     /**
-     * Returns Default subscription.
+     * Return an appropriate subscription ID for any situation.
+     *
+     * If this object has been created with {@link #createForSubscriptionId}, then the provided
+     * subId is returned. Otherwise, the preferred subId which is based on caller's context is
+     * returned.
+     * {@see SubscriptionManager#getDefaultDataSubscriptionId()}
+     * {@see SubscriptionManager#getDefaultVoiceSubscriptionId()}
+     * {@see SubscriptionManager#getDefaultSmsSubscriptionId()}
      */
-    private static int getDefaultSubscription() {
-        return SubscriptionManager.getDefaultSubscriptionId();
+    private int getSubId(int preferredSubId) {
+        if (SubscriptionManager.isUsableSubIdValue(mSubId)) {
+            return mSubId;
+        }
+        return preferredSubId;
     }
 
     /**
-     * Returns Default phone.
+     * Return an appropriate phone ID for any situation.
+     *
+     * If this object has been created with {@link #createForSubscriptionId}, then the phoneId
+     * associated with the provided subId is returned. Otherwise, the default phoneId associated
+     * with the default subId will be returned.
      */
-    private static int getDefaultPhone() {
-        return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId());
+    private int getPhoneId() {
+        return SubscriptionManager.getPhoneId(getSubId());
     }
 
     /**
-     *  @return default SIM's slot index. If SIM is not inserted, return default SIM slot index.
+     * Return an appropriate phone ID for any situation.
+     *
+     * If this object has been created with {@link #createForSubscriptionId}, then the phoneId
+     * associated with the provided subId is returned. Otherwise, return the phoneId associated
+     * with the preferred subId based on caller's context.
+     * {@see SubscriptionManager#getDefaultDataSubscriptionId()}
+     * {@see SubscriptionManager#getDefaultVoiceSubscriptionId()}
+     * {@see SubscriptionManager#getDefaultSmsSubscriptionId()}
+     */
+    private int getPhoneId(int preferredSubId) {
+        return SubscriptionManager.getPhoneId(getSubId(preferredSubId));
+    }
+
+    /**
+     * Return an appropriate slot index for any situation.
+     *
+     * if this object has been created with {@link #createForSubscriptionId}, then the slot index
+     * associated with the provided subId is returned. Otherwise, return the slot index associated
+     * with the default subId.
+     * If SIM is not inserted, return default SIM slot index.
      *
      * {@hide}
      */
     @VisibleForTesting
-    public int getDefaultSim() {
-        int slotIndex = SubscriptionManager.getSlotIndex(
-                SubscriptionManager.getDefaultSubscriptionId());
+    public int getSlotIndex() {
+        int slotIndex = SubscriptionManager.getSlotIndex(getSubId());
         if (slotIndex == SubscriptionManager.SIM_NOT_INSERTED) {
             slotIndex = SubscriptionManager.DEFAULT_SIM_SLOT_INDEX;
         }
@@ -4769,7 +4897,7 @@
     /** @hide */
     @SystemApi
     public List<String> getCarrierPackageNamesForIntent(Intent intent) {
-        return getCarrierPackageNamesForIntentAndPhone(intent, getDefaultPhone());
+        return getCarrierPackageNamesForIntentAndPhone(intent, getPhoneId());
     }
 
     /** @hide */
@@ -4965,6 +5093,80 @@
         return new int[0];
     }
 
+    public static abstract class OnReceiveUssdResponseCallback {
+       /**
+        ** Called when USSD has succeeded.
+        **/
+       public void onReceiveUssdResponse(String request, CharSequence response) {};
+
+       /**
+        ** Called when USSD has failed.
+        **/
+       public void onReceiveUssdResponseFailed(String request, int failureCode) {};
+    }
+
+    /**
+     * Sends an Unstructured Supplementary Service Data (USSD) request to the cellular network and
+     * informs the caller of the response via {@code callback}.
+     * <p>Carriers define USSD codes which can be sent by the user to request information such as
+     * the user's current data balance or minutes balance.
+     * <p>Requires permission:
+     * {@link android.Manifest.permission#CALL_PHONE}
+     * @param ussdRequest the USSD command to be executed.
+     * @param callback called by the framework to inform the caller of the result of executing the
+     *                 USSD request (see {@link OnReceiveUssdResponseCallback}).
+     * @param handler the {@link Handler} to run the request on.
+     */
+    @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+    public void sendUssdRequest(String ussdRequest,
+                                final OnReceiveUssdResponseCallback callback, Handler handler) {
+        checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null.");
+
+        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(getSubId(), ussdRequest, wrappedCallback);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#sendUSSDCode", e);
+            UssdResponse response = new UssdResponse(ussdRequest, "");
+            Bundle returnData = new Bundle();
+            returnData.putParcelable(USSD_RESPONSE, response);
+            wrappedCallback.send(USSD_ERROR_SERVICE_UNAVAIL, returnData);
+        }
+    }
+
+   /*
+    * @return true, if the device is currently on a technology (e.g. UMTS or LTE) which can support
+    * voice and data simultaneously. This can change based on location or network condition.
+    */
+    public boolean isConcurrentVoiceAndDataAllowed() {
+        try {
+            ITelephony telephony = getITelephony();
+            return (telephony == null ? false : telephony.isConcurrentVoiceAndDataAllowed(
+                    getSubId()));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isConcurrentVoiceAndDataAllowed", e);
+        }
+        return false;
+    }
+
     /** @hide */
     @SystemApi
     public boolean handlePinMmi(String dialString) {
@@ -5095,6 +5297,8 @@
 
     /**
      * Turns mobile data on or off.
+     * If this object has been created with {@link #createForSubscriptionId}, applies to the given
+     * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *
      * <p>Requires Permission:
      *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
@@ -5105,7 +5309,7 @@
      * @see #hasCarrierPrivileges
      */
     public void setDataEnabled(boolean enable) {
-        setDataEnabled(getSubId(), enable);
+        setDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable);
     }
 
     /** @hide */
@@ -5121,23 +5325,45 @@
         }
     }
 
+
+    /**
+     * @deprecated use {@link #isDataEnabled()} instead.
+     * @hide
+     */
+    @SystemApi
+    @Deprecated
+    public boolean getDataEnabled() {
+        return isDataEnabled();
+    }
+
     /**
      * Returns whether mobile data is enabled or not.
      *
-     * <p>Requires Permission:
-     *     {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
-     *     {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
-     *     calling app has carrier privileges.
+     * If this object has been created with {@link #createForSubscriptionId}, applies to the given
+     * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+     *
+     * <p>Requires one of the following permissions:
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
+     * calling app has carrier privileges.
+     *
+     * <p>Note that this does not take into account any data restrictions that may be present on the
+     * calling app. Such restrictions may be inspected with
+     * {@link ConnectivityManager#getRestrictBackgroundStatus}.
      *
      * @return true if mobile data is enabled.
      *
      * @see #hasCarrierPrivileges
      */
-    public boolean getDataEnabled() {
-        return getDataEnabled(getSubId());
+    @SuppressWarnings("deprecation")
+    public boolean isDataEnabled() {
+        return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
     }
 
-    /** @hide */
+    /**
+     * @deprecated use {@link #isDataEnabled(int)} instead.
+     * @hide
+     */
     @SystemApi
     public boolean getDataEnabled(int subId) {
         boolean retVal = false;
@@ -5381,7 +5607,7 @@
     * @hide
     */
     public void setSimOperatorNumeric(String numeric) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setSimOperatorNumericForPhone(phoneId, numeric);
     }
 
@@ -5401,7 +5627,7 @@
      * @hide
      */
     public void setSimOperatorName(String name) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setSimOperatorNameForPhone(phoneId, name);
     }
 
@@ -5421,7 +5647,7 @@
     * @hide
     */
     public void setSimCountryIso(String iso) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setSimCountryIsoForPhone(phoneId, iso);
     }
 
@@ -5441,7 +5667,7 @@
      * @hide
      */
     public void setSimState(String state) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setSimStateForPhone(phoneId, state);
     }
 
@@ -5466,7 +5692,7 @@
      * @hide
      **/
     public void setSimPowerState(boolean powerUp) {
-        setSimPowerStateForSlot(getDefaultSim(), powerUp);
+        setSimPowerStateForSlot(getSlotIndex(), powerUp);
     }
 
     /**
@@ -5500,7 +5726,7 @@
      * @hide
      */
     public void setBasebandVersion(String version) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setBasebandVersionForPhone(phoneId, version);
     }
 
@@ -5527,7 +5753,7 @@
      * @hide
      */
     public void setPhoneType(int type) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setPhoneType(phoneId, type);
     }
 
@@ -5555,7 +5781,7 @@
      * @hide
      */
     public String getOtaSpNumberSchema(String defaultValue) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         return getOtaSpNumberSchemaForPhone(phoneId, defaultValue);
     }
 
@@ -5586,7 +5812,7 @@
      * @hide
      */
     public boolean getSmsReceiveCapable(boolean defaultValue) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         return getSmsReceiveCapableForPhone(phoneId, defaultValue);
     }
 
@@ -5617,7 +5843,7 @@
      * @hide
      */
     public boolean getSmsSendCapable(boolean defaultValue) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         return getSmsSendCapableForPhone(phoneId, defaultValue);
     }
 
@@ -5645,7 +5871,7 @@
      * @hide
      */
     public void setNetworkOperatorName(String name) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setNetworkOperatorNameForPhone(phoneId, name);
     }
 
@@ -5667,7 +5893,7 @@
      * @hide
      */
     public void setNetworkOperatorNumeric(String numeric) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setNetworkOperatorNumericForPhone(phoneId, numeric);
     }
 
@@ -5687,7 +5913,7 @@
      * @hide
      */
     public void setNetworkRoaming(boolean isRoaming) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setNetworkRoamingForPhone(phoneId, isRoaming);
     }
 
@@ -5711,7 +5937,7 @@
      * @hide
      */
     public void setNetworkCountryIso(String iso) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId();
         setNetworkCountryIsoForPhone(phoneId, iso);
     }
 
@@ -5731,11 +5957,15 @@
 
     /**
      * Set the network type currently in use on the device for data transmission.
+     *
+     * If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * phoneId associated with the given subId. Otherwise, applies to the phoneId associated with
+     * {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      * @param type the network type currently in use on the device for data transmission
      * @hide
      */
     public void setDataNetworkType(int type) {
-        int phoneId = getDefaultPhone();
+        int phoneId = getPhoneId(SubscriptionManager.getDefaultDataSubscriptionId());
         setDataNetworkTypeForPhone(phoneId, type);
     }
 
@@ -5907,7 +6137,7 @@
      * @hide
      */
     public String getAidForAppType(int appType) {
-        return getAidForAppType(getDefaultSubscription(), appType);
+        return getAidForAppType(getSubId(), appType);
     }
 
     /**
@@ -5941,7 +6171,7 @@
      * @hide
      */
     public String getEsn() {
-        return getEsn(getDefaultSubscription());
+        return getEsn(getSubId());
     }
 
     /**
@@ -5974,7 +6204,7 @@
      * @hide
      */
     public String getCdmaPrlVersion() {
-        return getCdmaPrlVersion(getDefaultSubscription());
+        return getCdmaPrlVersion(getSubId());
     }
 
     /**
@@ -6072,7 +6302,7 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
         } catch (NullPointerException e) {
-            Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
+            Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
         }
         return new ArrayList<CarrierIdentifier>(0);
     }
diff --git a/telephony/java/android/telephony/UssdResponse.aidl b/telephony/java/android/telephony/UssdResponse.aidl
new file mode 100644
index 0000000..add28a0
--- /dev/null
+++ b/telephony/java/android/telephony/UssdResponse.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable UssdResponse;
diff --git a/telephony/java/android/telephony/UssdResponse.java b/telephony/java/android/telephony/UssdResponse.java
new file mode 100644
index 0000000..5df681d
--- /dev/null
+++ b/telephony/java/android/telephony/UssdResponse.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Represents the Ussd response, including
+ * the message and the return code.
+ * @hide
+ */
+public final class UssdResponse implements Parcelable {
+    private CharSequence mReturnMessage;
+    private String mUssdRequest;
+
+
+    /**
+     * Implement the Parcelable interface
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mUssdRequest);
+        TextUtils.writeToParcel(mReturnMessage, dest, 0);
+    }
+
+    public String getUssdRequest() {
+        return mUssdRequest;
+    }
+
+    public CharSequence getReturnMessage() {
+        return mReturnMessage;
+    }
+
+    /**
+     * Implement the Parcelable interface
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * * Initialize the object from the request and return message.
+     */
+    public UssdResponse(String ussdRequest, CharSequence returnMessage) {
+        mUssdRequest = ussdRequest;
+        mReturnMessage = returnMessage;
+    }
+
+    public static final Parcelable.Creator<UssdResponse> CREATOR = new Creator<UssdResponse>() {
+
+        @Override
+        public UssdResponse createFromParcel(Parcel in) {
+            String request = in.readString();
+            CharSequence message = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            return new UssdResponse(request, message);
+        }
+
+        @Override
+        public UssdResponse[] newArray(int size) {
+            return new UssdResponse[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/VisualVoicemailService.java b/telephony/java/android/telephony/VisualVoicemailService.java
new file mode 100644
index 0000000..84833e3
--- /dev/null
+++ b/telephony/java/android/telephony/VisualVoicemailService.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.MainThread;
+import android.annotation.SdkConstant;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.util.Log;
+
+/**
+ * This service is implemented by dialer apps that wishes to handle OMTP or similar visual
+ * voicemails. Telephony binds to this service when the cell service is first connected, a visual
+ * voicemail SMS has been received, or when a SIM has been removed. Telephony will only bind to the
+ * default dialer for such events (See {@link TelecomManager#getDefaultDialerPackage()}). The
+ * {@link android.service.carrier.CarrierMessagingService} precedes the VisualVoicemailService in
+ * the SMS filtering chain and may intercept the visual voicemail SMS before it reaches this
+ * service.
+ * <p>
+ * Below is an example manifest registration for a {@code VisualVoicemailService}.
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourVisualVoicemailServiceImplementation"
+ *          android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telephony.VisualVoicemailService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ */
+public abstract class VisualVoicemailService extends Service {
+
+    private static final String TAG = "VvmService";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+
+    /**
+     * @hide
+     */
+    public static final int MSG_ON_CELL_SERVICE_CONNECTED = 1;
+    /**
+     * @hide
+     */
+    public static final int MSG_ON_SMS_RECEIVED = 2;
+    /**
+     * @hide
+     */
+    public static final int MSG_ON_SIM_REMOVED = 3;
+    /**
+     * @hide
+     */
+    public static final int MSG_TASK_ENDED = 4;
+    /**
+     * @hide
+     */
+    public static final int MSG_TASK_STOPPED = 5;
+
+    /**
+     * @hide
+     */
+    public static final String DATA_PHONE_ACCOUNT_HANDLE = "data_phone_account_handle";
+    /**
+     * @hide
+     */
+    public static final String DATA_SMS = "data_sms";
+
+    /**
+     * Represents a visual voicemail event which needs to be handled. While the task is being
+     * processed telephony will hold a wakelock for the VisualVoicemailService. The service can
+     * unblock the main thread and pass the task to a worker thread. Once the task is finished,
+     * {@link VisualVoicemailTask#finish()} should be called to signal telephony to release the
+     * resources. Telephony will call {@link VisualVoicemailService#onStopped(VisualVoicemailTask)}
+     * when the task is going to be terminated before completion.
+     *
+     * @see #onCellServiceConnected(VisualVoicemailTask, PhoneAccountHandle)
+     * @see #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)
+     * @see #onSimRemoved(VisualVoicemailTask, PhoneAccountHandle)
+     * @see #onStopped(VisualVoicemailTask)
+     */
+    public static class VisualVoicemailTask {
+
+        private final int mTaskId;
+        private final Messenger mReplyTo;
+
+        private VisualVoicemailTask(Messenger replyTo, int taskId) {
+            mTaskId = taskId;
+            mReplyTo = replyTo;
+        }
+
+        /**
+         * Call to signal telephony the task has completed. Must be called for every task.
+         */
+        public final void finish() {
+            Message message = Message.obtain();
+            try {
+                message.what = MSG_TASK_ENDED;
+                message.arg1 = mTaskId;
+                mReplyTo.send(message);
+            } catch (RemoteException e) {
+                Log.e(TAG,
+                        "Cannot send MSG_TASK_ENDED, remote handler no longer exist");
+            }
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof VisualVoicemailTask)) {
+                return false;
+            }
+            return mTaskId == ((VisualVoicemailTask) obj).mTaskId;
+        }
+
+        @Override
+        public int hashCode() {
+            return mTaskId;
+        }
+    }
+
+    /**
+     * Handles messages sent by telephony.
+     */
+    private final Messenger mMessenger = new Messenger(new Handler() {
+        @Override
+        public void handleMessage(final Message msg) {
+            final PhoneAccountHandle handle = msg.getData()
+                    .getParcelable(DATA_PHONE_ACCOUNT_HANDLE);
+            VisualVoicemailTask task = new VisualVoicemailTask(msg.replyTo, msg.arg1);
+            switch (msg.what) {
+                case MSG_ON_CELL_SERVICE_CONNECTED:
+                    onCellServiceConnected(task, handle);
+                    break;
+                case MSG_ON_SMS_RECEIVED:
+                    VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS);
+                    onSmsReceived(task, sms);
+                    break;
+                case MSG_ON_SIM_REMOVED:
+                    onSimRemoved(task, handle);
+                    break;
+                case MSG_TASK_STOPPED:
+                    onStopped(task);
+                    break;
+                default:
+                    super.handleMessage(msg);
+                    break;
+            }
+        }
+    });
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    /**
+     * Called when the cellular service is connected on a {@link PhoneAccountHandle} for the first
+     * time, or when the carrier config has changed. It will not be called when the signal is lost
+     * then restored.
+     *
+     * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
+     * called when the task is completed.
+     * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event.
+     */
+    @MainThread
+    public abstract void onCellServiceConnected(VisualVoicemailTask task,
+                                                PhoneAccountHandle phoneAccountHandle);
+
+    /**
+     * Called when a SMS matching the {@link VisualVoicemailSmsFilterSettings} set by
+     * {@link #setSmsFilterSettings(Context, PhoneAccountHandle, VisualVoicemailSmsFilterSettings)}
+     * is received.
+     *
+     * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
+     * called when the task is completed.
+     * @param sms The content of the received SMS.
+     */
+    @MainThread
+    public abstract void onSmsReceived(VisualVoicemailTask task,
+                                       VisualVoicemailSms sms);
+
+    /**
+     * Called when a SIM is removed.
+     *
+     * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
+     * called when the task is completed.
+     * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event.
+     */
+    @MainThread
+    public abstract void onSimRemoved(VisualVoicemailTask task,
+                                      PhoneAccountHandle phoneAccountHandle);
+
+    /**
+     * Called before the system is about to terminate a task. The service should persist any
+     * necessary data and call finish on the task immediately.
+     */
+    @MainThread
+    public abstract void onStopped(VisualVoicemailTask task);
+
+    /**
+     * Set the visual voicemail SMS filter settings for the VisualVoicemailService.
+     * {@link #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be called when
+     * a SMS matching the settings is received. The caller should have
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} and implements a
+     * VisualVoicemailService.
+     * <p>
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param phoneAccountHandle The account to apply the settings to.
+     * @param settings The settings for the filter, or {@code null} to disable the filter.
+     */
+    public final static void setSmsFilterSettings(Context context,
+            PhoneAccountHandle phoneAccountHandle,
+            VisualVoicemailSmsFilterSettings settings) {
+        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+        int subId = getSubId(context, phoneAccountHandle);
+        if (settings == null) {
+            telephonyManager.disableVisualVoicemailSmsFilter(subId);
+        } else {
+            telephonyManager.enableVisualVoicemailSmsFilter(subId, settings);
+        }
+    }
+
+    /**
+     * Send a visual voicemail SMS. The caller must be the current default dialer.
+     * <p>
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#SEND_SMS SEND_SMS}
+     *
+     * @param phoneAccountHandle The account to send the SMS with.
+     * @param number The destination number.
+     * @param port The destination port for data SMS, or 0 for text SMS.
+     * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream.
+     * @param sentIntent The sent intent passed to the {@link SmsManager}
+     * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
+     * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
+     */
+    public final static void sendVisualVoicemailSms(Context context,
+            PhoneAccountHandle phoneAccountHandle, String number,
+            short port, String text, PendingIntent sentIntent) {
+        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+        telephonyManager.sendVisualVoicemailSmsForSubscriber(getSubId(context, phoneAccountHandle),
+                number, port, text, sentIntent);
+    }
+
+    private static int getSubId(Context context, PhoneAccountHandle phoneAccountHandle) {
+        TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+        TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+        return telephonyManager
+                .getSubIdForPhoneAccount(telecomManager.getPhoneAccount(phoneAccountHandle));
+    }
+
+}
diff --git a/telephony/java/android/telephony/VisualVoicemailSms.java b/telephony/java/android/telephony/VisualVoicemailSms.java
new file mode 100644
index 0000000..1e6ea4b
--- /dev/null
+++ b/telephony/java/android/telephony/VisualVoicemailSms.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.VisualVoicemailService.VisualVoicemailTask;
+
+/**
+ * Represents the content of a visual voicemail SMS. If a incoming SMS matches the {@link
+ * VisualVoicemailSmsFilterSettings} set by the default dialer, {@link
+ * VisualVoicemailService#onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be called.
+ */
+public final class VisualVoicemailSms implements Parcelable {
+
+    private final PhoneAccountHandle mPhoneAccountHandle;
+    @Nullable
+    private final String mPrefix;
+
+    @Nullable
+    private final Bundle mFields;
+
+    private final String mMessageBody;
+
+    VisualVoicemailSms(Builder builder) {
+        mPhoneAccountHandle = builder.mPhoneAccountHandle;
+        mPrefix = builder.mPrefix;
+        mFields = builder.mFields;
+        mMessageBody = builder.mMessageBody;
+    }
+
+    /**
+     * The {@link PhoneAccountHandle} that received the SMS.
+     */
+    public PhoneAccountHandle getPhoneAccountHandle() {
+        return mPhoneAccountHandle;
+    }
+
+    /**
+     * The event type of the SMS or {@code null} if the framework cannot parse the SMS as voicemail
+     * but the carrier pattern indicates it is. Common values are "SYNC" or "STATUS".
+     */
+    public String getPrefix() {
+        return mPrefix;
+    }
+
+    /**
+     * The key-value pairs sent by the SMS, or {@code null} if the framework cannot parse the SMS as
+     * voicemail but the carrier pattern indicates it is. The interpretation of the fields is
+     * carrier dependent.
+     */
+    public Bundle getFields() {
+        return mFields;
+    }
+
+    /**
+     * Raw message body of the received SMS.
+     */
+    public String getMessageBody() {
+        return mMessageBody;
+    }
+
+    /**
+     * Builder for the {@link VisualVoicemailSms}. Internal use only.
+     *
+     * @hide
+     */
+    public static class Builder {
+
+        private PhoneAccountHandle mPhoneAccountHandle;
+        private String mPrefix;
+        private Bundle mFields;
+        private String mMessageBody;
+
+        public VisualVoicemailSms build() {
+            return new VisualVoicemailSms(this);
+        }
+
+        public Builder setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+            this.mPhoneAccountHandle = phoneAccountHandle;
+            return this;
+        }
+
+        public Builder setPrefix(String prefix) {
+            this.mPrefix = prefix;
+            return this;
+        }
+
+        public Builder setFields(Bundle fields) {
+            this.mFields = fields;
+            return this;
+        }
+
+        public Builder setMessageBody(String messageBody) {
+            this.mMessageBody = messageBody;
+            return this;
+        }
+
+    }
+
+
+    public static final Creator<VisualVoicemailSms> CREATOR =
+            new Creator<VisualVoicemailSms>() {
+                @Override
+                public VisualVoicemailSms createFromParcel(Parcel in) {
+                    return new Builder()
+                            .setPhoneAccountHandle((PhoneAccountHandle) in.readParcelable(null))
+                            .setPrefix(in.readString())
+                            .setFields(in.readBundle())
+                            .setMessageBody(in.readString())
+                            .build();
+                }
+
+                @Override
+                public VisualVoicemailSms[] newArray(int size) {
+                    return new VisualVoicemailSms[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(getPhoneAccountHandle(), flags);
+        dest.writeString(getPrefix());
+        dest.writeBundle(getFields());
+        dest.writeString(getMessageBody());
+    }
+}
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index 5b81027..56a8c62 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -15,9 +15,12 @@
  */
 package android.telephony;
 
+import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import android.telecom.PhoneAccountHandle;
+import android.telephony.VisualVoicemailService.VisualVoicemailTask;
 import java.util.Collections;
 import java.util.List;
 
@@ -28,42 +31,44 @@
  * <p>[clientPrefix]:[prefix]:([key]=[value];)*
  *
  * <p>will be regarded as a visual voicemail SMS, and removed before reaching the SMS provider. The
- * intent {@link android.provider.VoicemailContract#ACTION_VOICEMAIL_SMS_RECEIVED} will then be sent
- * to the default dialer with the information extracted from the SMS.
+ * {@link VisualVoicemailService} in the current default dialer will be bound and
+ * {@link VisualVoicemailService#onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)}
+ * will called with the information extracted from the SMS.
  *
  * <p>Use {@link android.telephony.VisualVoicemailSmsFilterSettings.Builder} to construct this
  * class.
  *
- * @see android.telephony.TelephonyManager#enableVisualVoicemailSmsFilter
- *
- * @hide
+ * @see VisualVoicemailService#setSmsFilterSettings(Context, PhoneAccountHandle, VisualVoicemailSmsFilterSettings)
  */
-public class VisualVoicemailSmsFilterSettings implements Parcelable {
+public final class VisualVoicemailSmsFilterSettings implements Parcelable {
 
 
     /**
      * The visual voicemail SMS message does not have to be a data SMS, and can be directed to any
      * port.
-     *
-     * @hide
      */
     public static final int DESTINATION_PORT_ANY = -1;
 
     /**
      * The visual voicemail SMS message can be directed to any port, but must be a data SMS.
-     *
-     * @hide
      */
     public static final int DESTINATION_PORT_DATA_SMS = -2;
 
+    /**
+     * @hide
+     */
     public static final String DEFAULT_CLIENT_PREFIX = "//VVM";
+    /**
+     * @hide
+     */
     public static final List<String> DEFAULT_ORIGINATING_NUMBERS = Collections.emptyList();
+    /**
+     * @hide
+     */
     public static final int DEFAULT_DESTINATION_PORT = DESTINATION_PORT_ANY;
 
     /**
      * Builder class for {@link VisualVoicemailSmsFilterSettings} objects.
-     *
-     * @hide
      */
     public static class Builder {
 
@@ -171,4 +176,13 @@
         dest.writeInt(destinationPort);
     }
 
+    @Override
+    public String toString(){
+        return "[VisualVoicemailSmsFilterSettings "
+                + "clientPrefix=" + clientPrefix
+                + ", originatingNumbers=" + originatingNumbers
+                + ", destinationPort=" + destinationPort
+                + "]";
+    }
+
 }
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
index 38ea6e6f..a75cd86 100644
--- a/telephony/java/android/telephony/ims/ImsServiceProxy.java
+++ b/telephony/java/android/telephony/ims/ImsServiceProxy.java
@@ -120,7 +120,7 @@
     public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
             throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
                     incomingCallIntent, listener);
         }
@@ -129,7 +129,7 @@
     @Override
     public void endSession(int sessionId) throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
         }
     }
@@ -138,7 +138,7 @@
     public boolean isConnected(int callServiceType, int callType)
             throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
                     callServiceType, callType);
         }
@@ -147,7 +147,7 @@
     @Override
     public boolean isOpened() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
         }
     }
@@ -156,7 +156,7 @@
     public void addRegistrationListener(IImsRegistrationListener listener)
     throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
                     listener);
         }
@@ -166,7 +166,7 @@
     public void removeRegistrationListener(IImsRegistrationListener listener)
             throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
                     listener);
         }
@@ -176,7 +176,7 @@
     public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
             throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
                     sessionId, callServiceType, callType);
         }
@@ -186,7 +186,7 @@
     public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
             IImsCallSessionListener listener) throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
                     sessionId, profile, listener);
         }
@@ -196,7 +196,7 @@
     public IImsCallSession getPendingCallSession(int sessionId, String callId)
             throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
                     sessionId, callId);
         }
@@ -205,7 +205,7 @@
     @Override
     public IImsUt getUtInterface() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
         }
     }
@@ -213,7 +213,7 @@
     @Override
     public IImsConfig getConfigInterface() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
         }
     }
@@ -221,7 +221,7 @@
     @Override
     public void turnOnIms() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
         }
     }
@@ -229,7 +229,7 @@
     @Override
     public void turnOffIms() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
         }
     }
@@ -237,7 +237,7 @@
     @Override
     public IImsEcbm getEcbmInterface() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
         }
     }
@@ -246,7 +246,7 @@
     public void setUiTTYMode(int uiTtyMode, Message onComplete)
             throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
                     onComplete);
         }
@@ -255,7 +255,7 @@
     @Override
     public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
         synchronized (mLock) {
-            checkBinderConnection();
+            checkServiceIsReady();
             return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
                     mSupportedFeature);
         }
@@ -264,7 +264,8 @@
     @Override
     public int getFeatureStatus() {
         synchronized (mLock) {
-            if (mFeatureStatusCached != null) {
+            if (isBinderAlive() && mFeatureStatusCached != null) {
+                Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
                 return mFeatureStatusCached;
             }
         }
@@ -277,6 +278,7 @@
             // Cache only non-null value for feature status.
             mFeatureStatusCached = status;
         }
+        Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
         return status;
     }
 
@@ -301,10 +303,28 @@
         mStatusCallback = c;
     }
 
+    /**
+     * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
+     * method returns false, it doesn't mean that the Binder connection is not available (use
+     * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
+     * at this time.
+     *
+     * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
+     * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
+     */
+    public boolean isBinderReady() {
+        return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
+    }
+
     @Override
     public boolean isBinderAlive() {
-        return mIsAvailable && getFeatureStatus() == ImsFeature.STATE_READY && mBinder != null &&
-                mBinder.isBinderAlive();
+        return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
+    }
+
+    protected void checkServiceIsReady() throws RemoteException {
+        if (!isBinderReady()) {
+            throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
+        }
     }
 
     private IImsServiceController getServiceInterface(IBinder b) {
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 988dd58..395f1cc 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -150,7 +150,7 @@
     private void notifyFeatureState(@ImsState int state) {
         if (mStatusCallback != null) {
             try {
-                Log.i(LOG_TAG, "notifying ImsFeatureState");
+                Log.i(LOG_TAG, "notifying ImsFeatureState=" + state);
                 mStatusCallback.notifyImsFeatureStatus(state);
             } catch (RemoteException e) {
                 mStatusCallback = null;
diff --git a/telephony/java/android/telephony/mbms/DownloadCallback.java b/telephony/java/android/telephony/mbms/DownloadCallback.java
new file mode 100644
index 0000000..0c6fec4
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+/**
+ * A optional listener class used by download clients to track progress.
+ * @hide
+ */
+public class DownloadCallback extends IDownloadCallback.Stub {
+    /**
+     * Gives process callbacks for a given DownloadRequest.
+     * request indicates which download is being referenced.
+     * fileInfo gives information about the file being downloaded.  Note that
+     *   the request may result in many files being downloaded and the client
+     *   may not have been able to get a list of them in advance.
+     * downloadSize is the final amount to be downloaded.  This may be different
+     *   from the decoded final size, but is useful in gauging download progress.
+     * currentSize is the amount currently downloaded.
+     * decodedPercent is the percent from 0 to 100 of the file decoded.  After the
+     *   download completes the contents needs to be processed.  It is perhaps
+     *   uncompressed, transcoded and/or decrypted.  Generally the download completes
+     *   before the decode is started, but that's not required.
+     */
+    public void progress(DownloadRequest request, FileInfo fileInfo,
+            int downloadSize, int currentSize, int decodedPercent) {
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.aidl b/telephony/java/android/telephony/mbms/DownloadRequest.aidl
new file mode 100755
index 0000000..ece577d
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable DownloadRequest;
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
new file mode 100644
index 0000000..dbaf10bb
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.URISyntaxException;
+
+/**
+ * A Parcelable class describing a pending Cell-Broadcast download request
+ * @hide
+ */
+public class DownloadRequest implements Parcelable {
+    /** @hide */
+    public static class Builder {
+        private int id;
+        private FileServiceInfo serviceInfo;
+        private Uri source;
+        private Uri dest;
+        private int sub;
+        private String appIntent;
+
+        public Builder setId(int id) {
+            this.id = id;
+            return this;
+        }
+
+        public Builder setServiceInfo(FileServiceInfo serviceInfo) {
+            this.serviceInfo = serviceInfo;
+            return this;
+        }
+
+        public Builder setSource(Uri source) {
+            this.source = source;
+            return this;
+        }
+
+        public Builder setDest(Uri dest) {
+            this.dest = dest;
+            return this;
+        }
+
+        public Builder setSub(int sub) {
+            this.sub = sub;
+            return this;
+        }
+
+        public Builder setAppIntent(Intent intent) {
+            this.appIntent = intent.toUri(0);
+            return this;
+        }
+
+        public DownloadRequest build() {
+            return new DownloadRequest(id, serviceInfo, source, dest, sub, appIntent);
+        }
+    }
+
+    private final int downloadId;
+    private final FileServiceInfo fileServiceInfo;
+    private final Uri sourceUri;
+    private final Uri destinationUri;
+    private final int subId;
+    private final String serializedResultIntentForApp;
+
+    private DownloadRequest(int id, FileServiceInfo serviceInfo,
+            Uri source, Uri dest,
+            int sub, String appIntent) {
+        downloadId = id;
+        fileServiceInfo = serviceInfo;
+        sourceUri = source;
+        destinationUri = dest;
+        subId = sub;
+        serializedResultIntentForApp = appIntent;
+    }
+
+    public static DownloadRequest copy(DownloadRequest other) {
+        return new DownloadRequest(other);
+    }
+
+    private DownloadRequest(DownloadRequest dr) {
+        downloadId = dr.downloadId;
+        fileServiceInfo = dr.fileServiceInfo;
+        sourceUri = dr.sourceUri;
+        destinationUri = dr.destinationUri;
+        subId = dr.subId;
+        serializedResultIntentForApp = dr.serializedResultIntentForApp;
+    }
+
+    private DownloadRequest(Parcel in) {
+        downloadId = in.readInt();
+        fileServiceInfo = in.readParcelable(getClass().getClassLoader());
+        sourceUri = in.readParcelable(getClass().getClassLoader());
+        destinationUri = in.readParcelable(getClass().getClassLoader());
+        subId = in.readInt();
+        serializedResultIntentForApp = in.readString();
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(downloadId);
+        out.writeParcelable(fileServiceInfo, flags);
+        out.writeParcelable(sourceUri, flags);
+        out.writeParcelable(destinationUri, flags);
+        out.writeInt(subId);
+        out.writeString(serializedResultIntentForApp);
+    }
+
+    public int getDownloadId() {
+        return downloadId;
+    }
+
+    public FileServiceInfo getFileServiceInfo() {
+        return fileServiceInfo;
+    }
+
+    public Uri getSourceUri() {
+        return sourceUri;
+    }
+
+    public Uri getDestinationUri() {
+        return destinationUri;
+    }
+
+    public int getSubId() {
+        return subId;
+    }
+
+    public Intent getIntentForApp() {
+        try {
+            return Intent.parseUri(serializedResultIntentForApp, 0);
+        } catch (URISyntaxException e) {
+            return null;
+        }
+    }
+
+    public static final Parcelable.Creator<DownloadRequest> CREATOR =
+            new Parcelable.Creator<DownloadRequest>() {
+        public DownloadRequest createFromParcel(Parcel in) {
+            return new DownloadRequest(in);
+        }
+        public DownloadRequest[] newArray(int size) {
+            return new DownloadRequest[size];
+        }
+    };
+
+}
diff --git a/telephony/java/android/telephony/mbms/DownloadStatus.aidl b/telephony/java/android/telephony/mbms/DownloadStatus.aidl
new file mode 100755
index 0000000..e7cfd39
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadStatus.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable DownloadStatus;
diff --git a/telephony/java/android/telephony/mbms/DownloadStatus.java b/telephony/java/android/telephony/mbms/DownloadStatus.java
new file mode 100644
index 0000000..90eb53f
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadStatus.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A Parcelable class describing the status of a Cell-Broadcast download request
+ * @hide
+ */
+public class DownloadStatus implements Parcelable {
+    // includes downloads and active repair work
+    public final int activelyDownloading;
+
+    // files scheduled for future broadcast
+    public final int pendingDownloads;
+
+    // files scheduled for future repairs
+    public final int pendingRepairs;
+
+    // is a future download window scheduled with unknown
+    // number of files
+    public final boolean windowPending;
+
+    public DownloadStatus(int downloading, int downloads, int repairs, boolean window) {
+        activelyDownloading = downloading;
+        pendingDownloads = downloads;
+        pendingRepairs = repairs;
+        windowPending = window;
+    }
+
+    public static final Parcelable.Creator<DownloadStatus> CREATOR =
+            new Parcelable.Creator<DownloadStatus>() {
+        @Override
+        public DownloadStatus createFromParcel(Parcel in) {
+            return new DownloadStatus(in);
+        }
+
+        @Override
+        public DownloadStatus[] newArray(int size) {
+            return new DownloadStatus[size];
+        }
+    };
+
+    DownloadStatus(Parcel in) {
+        activelyDownloading = in.readInt();
+        pendingDownloads = in.readInt();
+        pendingRepairs = in.readInt();
+        windowPending = (in.readInt() == 1);
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(activelyDownloading);
+        dest.writeInt(pendingDownloads);
+        dest.writeInt(pendingRepairs);
+        dest.writeInt((windowPending ? 1 : 0));
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/FileInfo.aidl b/telephony/java/android/telephony/mbms/FileInfo.aidl
new file mode 100755
index 0000000..62926e1
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable FileInfo;
diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java
new file mode 100644
index 0000000..d3888bd
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileInfo.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A Parcelable class Cell-Broadcast downloadable file information.
+ * @hide
+ */
+public class FileInfo implements Parcelable {
+
+    /**
+     * The URI into the carriers infrastructure which points to this file.
+     * This is used internally but is also one of the few pieces of data about the content that is
+     * exposed and may be needed for disambiguation by the application.
+     */
+    final Uri uri;
+
+    /**
+     * The mime type of the content.
+     */
+    final String mimeType;
+
+    /**
+     * The size of the file in bytes.
+     */
+    final long size;
+
+    /**
+     * The MD5 hash of the file.
+     */
+    final byte md5Hash[];
+
+    /**
+     * Gets the parent service for this file.
+     */
+    public FileServiceInfo getFileServiceInfo() {
+        return null;
+    }
+
+    public static final Parcelable.Creator<FileInfo> CREATOR =
+            new Parcelable.Creator<FileInfo>() {
+        @Override
+        public FileInfo createFromParcel(Parcel source) {
+            return new FileInfo(source);
+        }
+
+        @Override
+        public FileInfo[] newArray(int size) {
+            return new FileInfo[size];
+        }
+    };
+
+    private FileInfo(Parcel in) {
+        uri = in.readParcelable(null);
+        mimeType = in.readString();
+        size = in.readLong();
+        int arraySize = in.readInt();
+        md5Hash = new byte[arraySize];
+        in.readByteArray(md5Hash);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(uri, flags);
+        dest.writeString(mimeType);
+        dest.writeLong(size);
+        dest.writeInt(md5Hash.length);
+        dest.writeByteArray(md5Hash);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.aidl b/telephony/java/android/telephony/mbms/FileServiceInfo.aidl
new file mode 100755
index 0000000..4646bad
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable FileServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
new file mode 100644
index 0000000..8bda370
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A Parcelable class Cell-Broadcast downloadable file information.
+ * @hide
+ */
+public class FileServiceInfo extends ServiceInfo implements Parcelable {
+    public List<FileInfo> files;
+
+    public FileServiceInfo(Map<Locale, String> newNames, String newClassName, Locale newLocale,
+            String newServiceId, Date start, Date end, List<FileInfo> newFiles) {
+        super(newNames, newClassName, newLocale, newServiceId, start, end);
+        files = new ArrayList(newFiles);
+    }
+
+    public static final Parcelable.Creator<FileServiceInfo> CREATOR =
+            new Parcelable.Creator<FileServiceInfo>() {
+        @Override
+        public FileServiceInfo createFromParcel(Parcel source) {
+            return new FileServiceInfo(source);
+        }
+
+        @Override
+        public FileServiceInfo[] newArray(int size) {
+            return new FileServiceInfo[size];
+        }
+    };
+
+    FileServiceInfo(Parcel in) {
+        super(in);
+        files = new ArrayList<FileInfo>();
+        in.readList(files, null);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeList(files);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/IDownloadCallback.aidl b/telephony/java/android/telephony/mbms/IDownloadCallback.aidl
new file mode 100755
index 0000000..a6bd7e5
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IDownloadCallback.aidl
@@ -0,0 +1,34 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.FileInfo;
+
+/**
+ * The optional interface used by download clients to track progress.
+ * @hide
+ */
+interface IDownloadCallback
+{
+    /**
+     * Gives progress callbacks for a given DownloadRequest.  Includes a FileInfo
+     * as the list of files may not have been known at request-time.
+     */
+    void progress(in DownloadRequest request, in FileInfo fileInfo, int downloadSize,
+            int currentSize, int decodedPercent);
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
new file mode 100755
index 0000000..03227d0
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
@@ -0,0 +1,42 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+import android.telephony.mbms.FileServiceInfo;
+
+import java.util.List;
+
+/**
+ * The interface the clients top-level file download listener will satisfy.
+ * @hide
+ */
+interface IMbmsDownloadManagerCallback
+{
+    void error(int errorCode, String message);
+
+    /**
+     * Called to indicate published File Services have changed.
+     *
+     * This will only be called after the application has requested
+     * a list of file services and specified a service class list
+     * of interest AND the results of a subsequent getFileServices
+     * call with the same service class list would
+     * return different
+     * results.
+     */
+    void fileServicesUpdated(in List<FileServiceInfo> services);
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
new file mode 100755
index 0000000..cbf0fca
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
@@ -0,0 +1,53 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+import android.telephony.mbms.StreamingServiceInfo;
+
+import java.util.List;
+
+/**
+ * The interface the clients top-level streaming listener will satisfy.
+ * @hide
+ */
+interface IMbmsStreamingManagerCallback
+{
+    void error(int errorCode, String message);
+
+    /**
+     * Called to indicate published Streaming Services have changed.
+     *
+     * This will only be called after the application has requested
+     * a list of streaming services and specified a service class list
+     * of interest AND the results of a subsequent getStreamServices
+     * call with the same service class list would
+     * return different
+     * results.
+     */
+    void streamingServicesUpdated(in List<StreamingServiceInfo> services);
+
+    /**
+     * Called to indicate the active Streaming Services have changed.
+     * 
+     * This will be caused whenever a new service starts streaming or whenever
+     * MbmsStreamServiceManager.getActiveStreamingServices is called.
+     *
+     * @param services a list of StreamingServiceInfos.  May be empty if
+     *                 there are no active StreamingServices
+     */
+    void activeStreamingServicesUpdated(in List<StreamingServiceInfo> services);
+}
diff --git a/core/java/android/bluetooth/le/IAdvertiserCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
old mode 100644
new mode 100755
similarity index 60%
rename from core/java/android/bluetooth/le/IAdvertiserCallback.aidl
rename to telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
index c58b1df..7b4ecf2
--- a/core/java/android/bluetooth/le/IAdvertiserCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
@@ -13,17 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.bluetooth.le;
 
-import android.bluetooth.le.AdvertiseSettings;
+package android.telephony.mbms;
+
+import android.net.Uri;
+import android.telephony.SignalStrength;
+import android.telephony.mbms.StreamingService;
 
 /**
- * Callback definitions for interacting with Advertiser
  * @hide
  */
-oneway interface IAdvertiserCallback {
-    void onAdvertiserRegistered(in int status, in int advertiserId);
-
-    void onMultiAdvertiseCallback(in int status, boolean isStart,
-                                  in AdvertiseSettings advertiseSettings);
+oneway interface IStreamingServiceCallback {
+    void error(int errorCode, String message);
+    void streamStateChanged(in StreamingService service, int state);
+    void uriUpdated(in Uri uri);
+    void signalStrengthUpdated(in SignalStrength signalStrength);
 }
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
new file mode 100644
index 0000000..16fafe4
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * A Parcelable class with Cell-Broadcast service information.
+ * @hide
+ */
+public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.Stub {
+
+    public final static int ERROR_CARRIER_NOT_SUPPORTED      = 1;
+    public final static int ERROR_UNABLE_TO_INITIALIZE       = 2;
+    public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY  = 3;
+
+
+    public void error(int errorCode, String message) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate published File Services have changed.
+     *
+     * This will only be called after the application has requested
+     * a list of file services and specified a service class list
+     * of interest AND the results of a subsequent getFileServices
+     * call with the same service class list would return different
+     * results.
+     *
+     * @param services a List of FileServiceInfos
+     *
+     */
+    public void fileServicesUpdated(List<FileServiceInfo> services) {
+        // default implementation empty
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsInitializationException.java b/telephony/java/android/telephony/mbms/MbmsInitializationException.java
new file mode 100644
index 0000000..1612bc9
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsInitializationException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.mbms;
+
+/** @hide */
+public class MbmsInitializationException extends Exception {
+    private final int mErrorCode;
+
+    /** @hide */
+    public MbmsInitializationException(int errorCode) {
+        super();
+        mErrorCode = errorCode;
+    }
+
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
new file mode 100644
index 0000000..b3bc814
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * A Parcelable class with Cell-Broadcast service information.
+ * @hide
+ */
+public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub {
+
+    public final static int ERROR_CARRIER_NOT_SUPPORTED      = 1;
+    public final static int ERROR_UNABLE_TO_INITIALIZE       = 2;
+    public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY  = 3;
+
+
+    public void error(int errorCode, String message) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate published Streaming Services have changed.
+     *
+     * This will only be called after the application has requested
+     * a list of streaming services and specified a service class list
+     * of interest AND the results of a subsequent getStreamServices
+     * call with the same service class list would return different
+     * results.
+     *
+     * @param services a List of StreamingServiceInfos
+     *
+     */
+    public void streamingServicesUpdated(List<StreamingServiceInfo> services) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate the active Streaming Services have changed.
+     *
+     * This will be caused whenever a new service starts streaming or whenever
+     * MbmsStreamServiceManager.getActiveStreamingServices is called.
+     *
+     * @param services a list of StreamingServiceInfos.  May be empty if
+     *                 there are no active StreamingServices
+     */
+    public void activeStreamingServicesUpdated(List<StreamingServiceInfo> services) {
+        // default implementation empty
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.aidl b/telephony/java/android/telephony/mbms/ServiceInfo.aidl
new file mode 100755
index 0000000..6661c26
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable ServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
new file mode 100644
index 0000000..cd2e46c
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A Parcelable class with Cell-Broadcast service information.
+ * @hide
+ */
+public class ServiceInfo implements Parcelable {
+    // arbitrary limit on the number of locale -> name pairs we support
+    final static int MAP_LIMIT = 50;
+    /**
+     * User displayable names listed by language.  Unmodifiable.
+     */
+    final Map<Locale, String> names;
+
+    /**
+     * The class name for this service - used to catagorize and filter
+     */
+    final String className;
+
+    /**
+     * The language for this service content
+     */
+    final Locale locale;
+
+    /**
+     * The carrier's identifier for the service.
+     */
+    final String serviceId;
+
+    /**
+     * The start time indicating when this service will be available.
+     */
+    final Date sessionStartTime;
+
+    /**
+     * The end time indicating when this sesion stops being available.
+     */
+    final Date sessionEndTime;
+
+
+    public ServiceInfo(Map<Locale, String> newNames, String newClassName, Locale newLocale,
+            String newServiceId, Date start, Date end) {
+        if (newNames == null || newNames.isEmpty() || TextUtils.isEmpty(newClassName)
+                || newLocale == null || TextUtils.isEmpty(newServiceId)
+                || start == null || end == null) {
+            throw new IllegalArgumentException("Bad ServiceInfo construction");
+        }
+        if (newNames.size() > MAP_LIMIT) {
+            throw new RuntimeException("bad map length" + newNames.size());
+        }
+        names = new HashMap(newNames.size());
+        names.putAll(newNames);
+        className = newClassName;
+        locale = (Locale)newLocale.clone();
+        serviceId = newServiceId;
+        sessionStartTime = (Date)start.clone();
+        sessionEndTime = (Date)end.clone();
+    }
+
+    public static final Parcelable.Creator<FileServiceInfo> CREATOR =
+            new Parcelable.Creator<FileServiceInfo>() {
+        @Override
+        public FileServiceInfo createFromParcel(Parcel source) {
+            return new FileServiceInfo(source);
+        }
+
+        @Override
+        public FileServiceInfo[] newArray(int size) {
+            return new FileServiceInfo[size];
+        }
+    };
+
+    ServiceInfo(Parcel in) {
+        int mapCount = in.readInt();
+        if (mapCount > MAP_LIMIT || mapCount < 0) {
+              throw new RuntimeException("bad map length" + mapCount);
+        }
+        names = new HashMap(mapCount);
+        while (mapCount-- > 0) {
+            Locale locale = (java.util.Locale) in.readSerializable();
+            String name = in.readString();
+            names.put(locale, name);
+        }
+        className = in.readString();
+        locale = (java.util.Locale) in.readSerializable();
+        serviceId = in.readString();
+        sessionStartTime = (java.util.Date) in.readSerializable();
+        sessionEndTime = (java.util.Date) in.readSerializable();
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        Set<Locale> keySet = names.keySet();
+        dest.writeInt(keySet.size());
+        for (Locale l : keySet) {
+            dest.writeSerializable(l);
+            dest.writeString(names.get(l));
+        }
+        dest.writeString(className);
+        dest.writeSerializable(locale);
+        dest.writeString(serviceId);
+        dest.writeSerializable(sessionStartTime);
+        dest.writeSerializable(sessionEndTime);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/StreamingService.aidl b/telephony/java/android/telephony/mbms/StreamingService.aidl
new file mode 100755
index 0000000..0c286f3
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingService.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable StreamingService;
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
new file mode 100644
index 0000000..8cc6043
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.SignalStrength;
+
+/**
+ * @hide
+ */
+public class StreamingService {
+
+    public final static int STATE_STOPPED = 1;
+    public final static int STATE_STARTED = 2;
+    public final static int STATE_STALLED = 3;
+
+    /**
+     */
+    StreamingService(StreamingServiceInfo streamingServiceInfo,
+            IStreamingServiceCallback listener) {
+    }
+
+    /**
+     * Retreive the Uri used to play this stream.
+     *
+     * This may throw a RemoteException.
+     */
+    public Uri getPlaybackUri() {
+        return null;
+    }
+
+    /**
+     * Retreive the info for this StreamingService.
+     */
+    public StreamingServiceInfo getInfo() {
+        return null;
+    }
+
+    /**
+     * Retreive the current state of this stream.
+     *
+     * This may throw a RemoteException.
+     */
+    public int getState() {
+        return STATE_STOPPED;
+    }
+
+    /**
+     * Stop streaming this service.  Terminal.
+     *
+     * This may throw a RemoteException.
+     */
+    public void stopStreaming() {
+    }
+
+    /**
+     * Switch this stream to a different service.  Used for smooth transitions.
+     *
+     * This may throw a RemoteException.
+     *
+     * Asynchronous errors through the listener include any of the errors except
+     * <li>ERROR_MSDC_UNABLE_TO_INITIALIZE</li>
+     */
+    public void switchStream(StreamingServiceInfo streamingServiceInfo) {
+    }
+
+    public void dispose() {
+    }
+
+    public static final Parcelable.Creator<StreamingService> CREATOR =
+            new Parcelable.Creator<StreamingService>() {
+        @Override
+        public StreamingService createFromParcel(Parcel in) {
+            return new StreamingService(in);
+        }
+
+        @Override
+        public StreamingService[] newArray(int size) {
+            return new StreamingService[size];
+        }
+    };
+
+    private StreamingService(Parcel in) {
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+}
+
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
new file mode 100644
index 0000000..7f5c486
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.net.Uri;
+import android.telephony.SignalStrength;
+
+/**
+ * A Callback class for use when the applicaiton is actively streaming content.
+ * @hide
+ */
+public class StreamingServiceCallback extends IStreamingServiceCallback.Stub {
+
+
+    public void error(int errorCode, String message) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate this stream has changed state.
+     *
+     * See {@link StreamingService#STATE_STOPPED}, {@link StreamingService#STATE_STARTED}
+     * and {@link StreamingService#STATE_STALLED}.
+     */
+    public void streamStateChanged(StreamingService service, int state) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate published Download Services have changed.
+     *
+     * This may be called when a looping stream hits the end or
+     * when the a new URI should be used to correct for time drift.
+     */
+    public void uriUpdated(Uri uri) {
+        // default implementation empty
+    }
+
+    /**
+     * Signal Strength updated.
+     *
+     * This signal strength is the BROADCAST signal strength which,
+     * depending on technology in play and it's deployment, may be
+     * stronger or weaker than the traditional UNICAST signal
+     * strength.
+     *
+     * A {@link android.telephony.SignalStrength#getLevel} result of 0 means
+     * you don't have coverage for this stream, either due to geographic
+     * restrictions, poor tower coverage or something (yards of concrete?)
+     * interferring with the signal.
+     */
+    public void signalStrengthUpdated(SignalStrength signalStrength) {
+        // default implementation empty
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl b/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl
new file mode 100755
index 0000000..b902f27
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable StreamingServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
new file mode 100644
index 0000000..f559585
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A Parcelable class Cell-Broadcast media stream information.
+ * This may not have any more info than ServiceInfo, but kept for completeness.
+ * @hide
+ */
+public class StreamingServiceInfo extends ServiceInfo implements Parcelable {
+
+    public StreamingServiceInfo(Map<Locale, String> newNames, String newClassName,
+            Locale newLocale, String newServiceId, Date start, Date end) {
+        super(newNames, newClassName, newLocale, newServiceId, start, end);
+    }
+
+    public static final Parcelable.Creator<StreamingServiceInfo> CREATOR =
+            new Parcelable.Creator<StreamingServiceInfo>() {
+        @Override
+        public StreamingServiceInfo createFromParcel(Parcel source) {
+            return new StreamingServiceInfo(source);
+        }
+
+        @Override
+        public StreamingServiceInfo[] newArray(int size) {
+            return new StreamingServiceInfo[size];
+        }
+    };
+
+    StreamingServiceInfo(Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.aidl b/telephony/java/android/telephony/mbms/UriPathPair.aidl
new file mode 100755
index 0000000..8bf76824
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/UriPathPair.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms;
+
+parcelable UriPathPair;
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.java b/telephony/java/android/telephony/mbms/UriPathPair.java
new file mode 100644
index 0000000..7acc270
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/UriPathPair.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.mbms;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class UriPathPair implements Parcelable {
+    private final Uri mFilePathUri;
+    private final Uri mContentUri;
+
+    /** @hide */
+    public UriPathPair(Uri fileUri, Uri contentUri) {
+        if (fileUri == null || !ContentResolver.SCHEME_FILE.equals(fileUri.getScheme())) {
+            throw new IllegalArgumentException("File URI must have file scheme");
+        }
+        if (contentUri == null || !ContentResolver.SCHEME_CONTENT.equals(contentUri.getScheme())) {
+            throw new IllegalArgumentException("Content URI must have content scheme");
+        }
+
+        mFilePathUri = fileUri;
+        mContentUri = contentUri;
+    }
+
+    /** @hide */
+    protected UriPathPair(Parcel in) {
+        mFilePathUri = in.readParcelable(Uri.class.getClassLoader());
+        mContentUri = in.readParcelable(Uri.class.getClassLoader());
+    }
+
+    public static final Creator<UriPathPair> CREATOR = new Creator<UriPathPair>() {
+        @Override
+        public UriPathPair createFromParcel(Parcel in) {
+            return new UriPathPair(in);
+        }
+
+        @Override
+        public UriPathPair[] newArray(int size) {
+            return new UriPathPair[size];
+        }
+    };
+
+    /** future systemapi */
+    public Uri getFilePathUri() {
+        return mFilePathUri;
+    }
+
+    /** future systemapi */
+    public Uri getContentUri() {
+        return mContentUri;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mFilePathUri, flags);
+        dest.writeParcelable(mContentUri, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
new file mode 100755
index 0000000..3090e12
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -0,0 +1,73 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms.vendor;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.IDownloadCallback;
+
+/**
+ * The interface the opaque MbmsStreamingService will satisfy.
+ * @hide
+ */
+interface IMbmsDownloadService
+{
+    /**
+     * Initialize download service
+     * Registers this listener, subId with this appName
+     *
+     * No return value.  Async errors may be reported, but none expected (not doing anything yet).
+     */
+    void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener);
+
+    /**
+     * - Registers serviceClasses of interest with the uid/appName/subId key.
+     * - Starts asynch fetching data on download services of matching classes to be reported
+     * later by callback.
+     *
+     * Note that subsequent calls with the same callback, appName, subId and uid will replace
+     * the service class list.
+     */
+    int getFileServices(String appName, int subId, in List<String> serviceClasses);
+
+    /**
+     * should move the params into a DownloadRequest parcelable
+     */
+    int download(String appName, in DownloadRequest downloadRequest, IDownloadCallback listener);
+
+    List<DownloadRequest> listPendingDownloads(String appName);
+
+    int cancelDownload(String appName, in DownloadRequest downloadRequest);
+
+    DownloadStatus getDownloadStatus(String appName, in DownloadRequest downloadRequest);
+
+    /*
+     * named this for 2 reasons:
+     *  1 don't want 'State' here as it conflicts with 'Status' of the previous function
+     *  2 want to perfect typing 'Knowledge'
+     */
+    void resetDownloadKnowledge(String appName, in DownloadRequest downloadRequest);
+
+    /**
+     * End of life for this MbmsDownloadManager.
+     * Any pending downloads remain in affect and may start up independently in the future.
+     */
+    void dispose(String appName, int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
new file mode 100755
index 0000000..fbc0931
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -0,0 +1,88 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IStreamingServiceCallback;
+import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.StreamingServiceInfo;
+import android.telephony.SignalStrength;
+
+/**
+ * The interface the opaque MbmsStreamingService will satisfy.
+ * @hide
+ */
+interface IMbmsStreamingService
+{
+    /**
+     * Initialize streaming service
+     * Registers this listener, subId with this appName
+     *
+     */
+    int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId);
+
+
+    /**
+     * - Registers serviceClasses of interest with the uid/appName/subId key.
+     * - Starts asynch fetching data on streaming services of matching classes to be reported
+     * later by callback.
+     *
+     * Note that subsequent calls with the same callback, appName, subId and uid will replace
+     * the service class list.
+     */
+    int getStreamingServices(String appName, int subId, in List<String> serviceClasses);
+
+    /**
+     * - Starts streaming the serviceId given.
+     * - if the uid/appName/subId don't match a previously registered callback an error will
+     *   be returned
+     * - Streaming status will be sent via the included listener, including an initial
+     *   URL-change and State-change pair.
+     */
+    StreamingService startStreaming(String appName, int subId, String serviceId,
+            IStreamingServiceCallback listener);
+
+    /**
+     * Asynchronously fetches all Services being streamed by this uid/appName/subId.
+     */
+    int getActiveStreamingServices(String appName, int subId);
+
+
+    /**
+     * Per-stream api.  Note each specifies what stream they apply to.
+     */
+
+    Uri getPlaybackUri(String appName, int subId, String serviceId);
+
+    void switchStreams(String appName, int subId, String oldServiceId, String newServiceId);
+
+    int getState(String appName, int subId, String serviceId);
+
+    void stopStreaming(String appName, int subId, String serviceId);
+
+    void disposeStream(String appName, int subId, String serviceId);
+
+
+    /**
+     * End of life for all MbmsStreamingManager's created by this uid/appName/subId.
+     * Ends any streams run under this uid/appname/subId and calls the disposed methods
+     * an callbacks registered for this uid/appName/subId and the disposed methods on any
+     * listeners registered with startStreaming.
+     */
+    void dispose(String appName, int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
new file mode 100644
index 0000000..369aef1
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.mbms.vendor;
+
+import android.os.RemoteException;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.IDownloadCallback;
+import android.telephony.mbms.IMbmsDownloadManagerCallback;
+
+import java.util.List;
+
+/**
+ * Base class for MbmsDownloadService. The middleware should extend this base class rather than
+ * the aidl stub for compatibility
+ * @hide
+ * TODO: future systemapi
+ */
+public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
+    @Override
+    public void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener)
+            throws RemoteException {
+    }
+
+    @Override
+    public int getFileServices(String appName, int subId, List<String> serviceClasses) throws
+            RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int download(String appName, DownloadRequest downloadRequest, IDownloadCallback listener)
+            throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public List<DownloadRequest> listPendingDownloads(String appName) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public int cancelDownload(String appName, DownloadRequest downloadRequest)
+            throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public DownloadStatus getDownloadStatus(String appName, DownloadRequest downloadRequest)
+            throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void resetDownloadKnowledge(String appName, DownloadRequest downloadRequest)
+            throws RemoteException {
+    }
+
+    @Override
+    public void dispose(String appName, int subId) throws RemoteException {
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
new file mode 100644
index 0000000..1c8ab7c
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IStreamingServiceCallback;
+import android.telephony.mbms.StreamingService;
+
+import java.util.List;
+
+/**
+ * @hide
+ * TODO: future systemapi
+ */
+public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
+
+    @Override
+    public int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId)
+            throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int getStreamingServices(String appName, int subId, List<String> serviceClasses)
+            throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public StreamingService startStreaming(String appName, int subId,
+            String serviceId, IStreamingServiceCallback listener) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public int getActiveStreamingServices(String appName, int subId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public Uri getPlaybackUri(String appName, int subId, String serviceId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void switchStreams(String appName, int subId, String oldServiceId, String newServiceId)
+            throws RemoteException {
+    }
+
+    @Override
+    public int getState(String appName, int subId, String serviceId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void stopStreaming(String appName, int subId, String serviceId) throws RemoteException {
+    }
+
+    @Override
+    public void disposeStream(String appName, int subId, String serviceId) throws RemoteException {
+    }
+
+    @Override
+    public void dispose(String appName, int subId) throws RemoteException {
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c6b750e..f2e1e26 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -273,6 +274,16 @@
      */
     boolean handlePinMmi(String dialString);
 
+
+    /**
+     * 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(int subId, String ussdRequest, in ResultReceiver wrappedCallback);
+
     /**
      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
      * without SEND (so <code>dial</code> is not appropriate) for
@@ -481,12 +492,20 @@
      */
     int getVoiceMessageCountForSubscriber(int subId);
 
+    /**
+      * Returns true if current state supports both voice and data
+      * simultaneously. This can change based on location or network condition.
+      */
+    boolean isConcurrentVoiceAndDataAllowed(int subId);
+
     oneway void setVisualVoicemailEnabled(String callingPackage,
             in PhoneAccountHandle accountHandle, boolean enabled);
 
     boolean isVisualVoicemailEnabled(String callingPackage,
             in PhoneAccountHandle accountHandle);
 
+    String getVisualVoicemailPackageName(String callingPackage, int subId);
+
     // Not oneway, caller needs to make sure the vaule is set before receiving a SMS
     void enableVisualVoicemailSmsFilter(String callingPackage, int subId,
             in VisualVoicemailSmsFilterSettings settings);
@@ -497,9 +516,18 @@
     VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(String callingPackage,
             int subId);
 
-    // Get settings set by the package, requires READ_PRIVILEGED_PHONE_STATE permission
-    VisualVoicemailSmsFilterSettings getSystemVisualVoicemailSmsFilterSettings(String packageName,
-            int subId);
+    /**
+     *  Get settings set by the current default dialer, Internal use only.
+     *  Requires READ_PRIVILEGED_PHONE_STATE permission.
+     */
+    VisualVoicemailSmsFilterSettings getActiveVisualVoicemailSmsFilterSettings(int subId);
+
+    /**
+     * Send a visual voicemail SMS. Internal use only.
+     * Requires caller to be the default dialer and have SEND_SMS permission
+     */
+    oneway void sendVisualVoicemailSmsForSubscriber(in String callingPackage, in int subId,
+            in String number, in int port, in String text, in PendingIntent sentIntent);
 
     /**
      * Returns the network type for data transmission
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 1e1d7a6..954b17f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -414,6 +414,7 @@
     int RIL_REQUEST_SEND_DEVICE_STATE = 138;
     int RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER = 139;
     int RIL_REQUEST_SET_SIM_CARD_POWER = 140;
+    int RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION = 141;
 
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
 
@@ -465,4 +466,5 @@
     int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
     int RIL_UNSOL_LCEDATA_RECV = 1045;
     int RIL_UNSOL_PCO_DATA = 1046;
+    int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1047;
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index ce4e7e2..55a8b0b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -402,7 +402,7 @@
      * <ul>
      *   <li>apnType</li><dd>A string with the apn type.</dd>
      *   <li>redirectionUrl</li><dd>redirection url string</dd>
-     *   <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
+     *   <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system.</p>
      */
@@ -415,7 +415,7 @@
      * <ul>
      *   <li>apnType</li><dd>A string with the apn type.</dd>
      *   <li>errorCode</li><dd>A integer with dataFailCause.</dd>
-     *   <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
+     *   <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
@@ -432,13 +432,25 @@
      *                        IPV4V6)</dd>
      *   <li>pcoId</li><dd>An integer indicating the pco id for the data.</dd>
      *   <li>pcoValue</li><dd>A byte array of pco data read from modem.</dd>
-     *   <li>subId</dt><li>Sub Id which associated the data connection.</dd>
+     *   <li>subId</li><dd>Sub Id which associated the data connection.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
     public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
             "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
 
+    /**
+     * <p>Broadcast Action: when framework reset all carrier actions on sim load or absent.
+     * intended for carrier apps clean up (clear UI e.g.) and only sent to the specified carrier app
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent by the system.</p>
+     */
+    public static final String ACTION_CARRIER_SIGNAL_RESET =
+            "com.android.internal.telephony.CARRIER_SIGNAL_RESET";
+
     // CARRIER_SIGNAL_ACTION extra keys
     public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
     public static final String EXTRA_ERROR_CODE_KEY = "errorCode";
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
new file mode 100644
index 0000000..e3b06c8
--- /dev/null
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
+import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+import android.net.NetworkCapabilities;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkCapabilitiesTest {
+    @Test
+    public void testMaybeMarkCapabilitiesRestricted() {
+        // verify EIMS is restricted
+        assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
+                (1 << NET_CAPABILITY_EIMS));
+
+        // verify CBS is also restricted
+        assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
+                (1 << NET_CAPABILITY_CBS));
+
+        // verify default is not restricted
+        assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
+
+        // just to see
+        assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
+
+        // check that internet does not get restricted
+        NetworkCapabilities netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+        // metered-ness shouldn't matter
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+        // add EIMS - bundled with unrestricted means it's unrestricted
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NET_CAPABILITY_EIMS);
+        netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_INTERNET);
+        netCap.addCapability(NET_CAPABILITY_EIMS);
+        netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+        // just a restricted cap should be restricted regardless of meteredness
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_EIMS);
+        netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_EIMS);
+        netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+        // try 2 restricted caps
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_CBS);
+        netCap.addCapability(NET_CAPABILITY_EIMS);
+        netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+        netCap = new NetworkCapabilities();
+        netCap.addCapability(NET_CAPABILITY_CBS);
+        netCap.addCapability(NET_CAPABILITY_EIMS);
+        netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.maybeMarkCapabilitiesRestricted();
+        assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+    }
+
+}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 91d6c68..d4896264 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -39,6 +39,8 @@
 
 import com.android.frameworks.tests.net.R;
 import com.android.internal.util.HexDump;
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.internal.util.BitUtils.put;
 
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -65,7 +67,7 @@
  * Tests for APF program generator and interpreter.
  *
  * Build, install and run with:
- *  runtest frameworks-services -c android.net.apf.ApfTest
+ *  runtest frameworks-net -c android.net.apf.ApfTest
  */
 public class ApfTest extends AndroidTestCase {
     private static final int TIMEOUT_MS = 500;
@@ -1235,15 +1237,6 @@
             byte[] apf_program);
 
     @SmallTest
-    public void testBytesToInt() {
-        assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR));
-        assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS));
-        assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR));
-        assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR));
-        assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR));
-        assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR));
-    }
-
     public void testBroadcastAddress() throws Exception {
         assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
         assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
@@ -1257,7 +1250,7 @@
     }
 
     public void assertEqualsIp(String expected, int got) throws Exception {
-        int want = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress());
+        int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
         assertEquals(want, got);
     }
 }
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
new file mode 100644
index 0000000..063cd5dc
--- /dev/null
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.nsd;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.HandlerThread;
+import android.os.Handler;
+import android.os.Looper;
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.os.Message;
+import android.os.Messenger;
+import com.android.internal.util.AsyncChannel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NsdManagerTest {
+
+    static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
+
+    @Mock Context mContext;
+    @Mock INsdManager mService;
+    MockServiceHandler mServiceHandler;
+
+    long mTimeoutMs = 100; // non-final so that tests can adjust the value.
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mServiceHandler = spy(MockServiceHandler.create(mContext));
+        when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
+    }
+
+    @Test
+    public void testResolveService() {
+        NsdManager manager = makeManager();
+
+        NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+        NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
+        NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
+
+        manager.resolveService(request, listener);
+        int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+        int err = 33;
+        sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
+        verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
+
+        manager.resolveService(request, listener);
+        int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+        sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+        verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+    }
+
+    @Test
+    public void testParallelResolveService() {
+        NsdManager manager = makeManager();
+
+        NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+        NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
+
+        NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
+        NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
+
+        manager.resolveService(request, listener1);
+        int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+
+        manager.resolveService(request, listener2);
+        int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+
+        sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+        sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
+
+        verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+        verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+    }
+
+    @Test
+    public void testRegisterService() {
+        NsdManager manager = makeManager();
+
+        NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
+        NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
+        request1.setPort(2201);
+        request2.setPort(2202);
+        NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
+        NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
+
+        // Register two services
+        manager.registerService(request1, PROTOCOL, listener1);
+        int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
+
+        manager.registerService(request2, PROTOCOL, listener2);
+        int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
+
+        // First reques fails, second request succeeds
+        sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
+        verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
+
+        int err = 1;
+        sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
+        verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
+
+        // Client retries first request, it succeeds
+        manager.registerService(request1, PROTOCOL, listener1);
+        int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
+
+        sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
+        verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
+
+        // First request is unregistered, it succeeds
+        manager.unregisterService(listener1);
+        int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+        assertEquals(key3, key3again);
+
+        sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
+        verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
+
+        // Second request is unregistered, it fails
+        manager.unregisterService(listener2);
+        int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+        assertEquals(key2, key2again);
+
+        sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
+        verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
+
+        // TODO: do not unregister listener until service is unregistered
+        // Client retries unregistration of second request, it succeeds
+        //manager.unregisterService(listener2);
+        //int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+        //assertEquals(key2, key2yetAgain);
+
+        //sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
+        //verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
+    }
+
+    @Test
+    public void testDiscoverService() {
+        NsdManager manager = makeManager();
+
+        NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
+        NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
+        NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
+
+        NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
+
+        // Client registers for discovery, request fails
+        manager.discoverServices("a_type", PROTOCOL, listener);
+        int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+
+        int err = 1;
+        sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
+        verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
+
+        // Client retries, request succeeds
+        manager.discoverServices("a_type", PROTOCOL, listener);
+        int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+
+        sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
+        verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
+
+
+        // mdns notifies about services
+        sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
+        verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
+
+        sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
+        verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
+
+        sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
+        verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
+
+
+        // Client unregisters its listener
+        manager.stopServiceDiscovery(listener);
+        int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
+        assertEquals(key2, key2again);
+
+        // TODO: unregister listener immediately and stop notifying it about services
+        // Notifications are still passed to the client's listener
+        sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
+        verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
+
+        // Client is notified of complete unregistration
+        sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
+        verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
+
+        // Notifications are not passed to the client anymore
+        sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
+        verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
+
+
+        // Client registers for service discovery
+        reset(listener);
+        manager.discoverServices("a_type", PROTOCOL, listener);
+        int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+
+        sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
+        verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
+
+        // Client unregisters immediately, it fails
+        manager.stopServiceDiscovery(listener);
+        int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
+        assertEquals(key3, key3again);
+
+        err = 2;
+        sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
+        verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
+
+        // New notifications are not passed to the client anymore
+        sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
+        verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
+    }
+
+    @Test
+    public void testInvalidCalls() {
+        NsdManager manager = new NsdManager(mContext, mService);
+
+        NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
+        NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
+        NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
+
+        NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
+        NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
+        validService.setPort(2222);
+
+        // Service registration
+        //  - invalid arguments
+        mustFail(() -> { manager.unregisterService(null); });
+        mustFail(() -> { manager.registerService(null, -1, null); });
+        mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
+        mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
+        mustFail(() -> { manager.registerService(validService, -1, listener1); });
+        mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
+        manager.registerService(validService, PROTOCOL, listener1);
+        //  - listener already registered
+        mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
+        manager.unregisterService(listener1);
+        // TODO: make listener immediately reusable
+        //mustFail(() -> { manager.unregisterService(listener1); });
+        //manager.registerService(validService, PROTOCOL, listener1);
+
+        // Discover service
+        //  - invalid arguments
+        mustFail(() -> { manager.stopServiceDiscovery(null); });
+        mustFail(() -> { manager.discoverServices(null, -1, null); });
+        mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
+        mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
+        mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
+        manager.discoverServices("a_service", PROTOCOL, listener2);
+        //  - listener already registered
+        mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
+        manager.stopServiceDiscovery(listener2);
+        // TODO: make listener immediately reusable
+        //mustFail(() -> { manager.stopServiceDiscovery(listener2); });
+        //manager.discoverServices("another_service", PROTOCOL, listener2);
+
+        // Resolver service
+        //  - invalid arguments
+        mustFail(() -> { manager.resolveService(null, null); });
+        mustFail(() -> { manager.resolveService(null, listener3); });
+        mustFail(() -> { manager.resolveService(invalidService, listener3); });
+        mustFail(() -> { manager.resolveService(validService, null); });
+        manager.resolveService(validService, listener3);
+        //  - listener already registered:w
+        mustFail(() -> { manager.resolveService(validService, listener3); });
+    }
+
+    public void mustFail(Runnable fn) {
+        try {
+            fn.run();
+            fail();
+        } catch (Exception expected) {
+        }
+    }
+
+    NsdManager makeManager() {
+        NsdManager manager = new NsdManager(mContext, mService);
+        // Acknowledge first two messages connecting the AsyncChannel.
+        verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
+        reset(mServiceHandler);
+        assertNotNull(mServiceHandler.chan);
+        return manager;
+    }
+
+    int verifyRequest(int expectedMessageType) {
+        verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
+        reset(mServiceHandler);
+        Message received = mServiceHandler.lastMessage;
+        assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
+        return received.arg2;
+    }
+
+    void sendResponse(int replyType, int arg, int key, Object obj) {
+        mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
+    }
+
+    // Implements the server side of AsyncChannel connection protocol
+    public static class MockServiceHandler extends Handler {
+        public Context mContext;
+        public AsyncChannel chan;
+        public Message lastMessage;
+
+        MockServiceHandler(Looper looper, Context context) {
+            super(looper);
+            mContext = context;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            lastMessage = obtainMessage();
+            lastMessage.copyFrom(msg);
+            if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
+                chan = new AsyncChannel();
+                chan.connect(mContext, this, msg.replyTo);
+                chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
+            }
+
+        }
+
+        public static MockServiceHandler create(Context context) {
+            HandlerThread t = new HandlerThread("mock-service-handler");
+            t.start();
+            return new MockServiceHandler(t.getLooper(), context);
+        }
+    }
+}
diff --git a/tests/net/java/android/net/nsd/NsdServiceTest.java b/tests/net/java/android/net/nsd/NsdServiceTest.java
new file mode 100644
index 0000000..acc390c
--- /dev/null
+++ b/tests/net/java/android/net/nsd/NsdServiceTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.test.TestLooper;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.net.nsd.NsdManager;
+import com.android.server.NsdService.DaemonConnection;
+import com.android.server.NsdService.DaemonConnectionSupplier;
+import com.android.server.NsdService.NativeCallbackReceiver;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+// TODOs:
+//  - test client disconnects
+//  - test client can send requests and receive replies
+//  - test NSD_ON ENABLE/DISABLED listening
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NsdServiceTest {
+
+    @Mock Context mContext;
+    @Mock ContentResolver mResolver;
+    @Mock NsdService.NsdSettings mSettings;
+    @Mock DaemonConnection mDaemon;
+    NativeCallbackReceiver mDaemonCallback;
+    TestLooper mLooper;
+    TestHandler mHandler;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mLooper = new TestLooper();
+        mHandler = new TestHandler(mLooper.getLooper());
+        when(mContext.getContentResolver()).thenReturn(mResolver);
+    }
+
+    @Test
+    public void testClientsCanConnect() {
+        when(mSettings.isEnabled()).thenReturn(true);
+
+        NsdService service = makeService();
+
+        NsdManager client1 = connectClient(service);
+        verify(mDaemon, timeout(100).times(1)).execute("start-service");
+
+        NsdManager client2 = connectClient(service);
+
+        // TODO: disconnect client1
+        // TODO: disconnect client2
+    }
+
+    NsdService makeService() {
+        DaemonConnectionSupplier supplier = (callback) -> {
+            mDaemonCallback = callback;
+            return mDaemon;
+        };
+        NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
+        verify(mDaemon, never()).execute(any(String.class));
+        return service;
+    }
+
+    NsdManager connectClient(NsdService service) {
+        mLooper.startAutoDispatch();
+        NsdManager client = new NsdManager(mContext, service);
+        mLooper.stopAutoDispatch();
+        return client;
+    }
+
+    public static class TestHandler extends Handler {
+        public Message lastMessage;
+
+        TestHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            lastMessage = obtainMessage();
+            lastMessage.copyFrom(msg);
+        }
+    }
+}
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/net/java/com/android/internal/util/BitUtilsTest.java
new file mode 100644
index 0000000..0ad8a21
--- /dev/null
+++ b/tests/net/java/com/android/internal/util/BitUtilsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import java.nio.ByteBuffer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static com.android.internal.util.BitUtils.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitUtilsTest {
+
+    @Test
+    public void testUnsignedByteWideningConversions() {
+        byte b0 = 0;
+        byte b1 = 1;
+        byte bm1 = -1;
+        assertEquals(0, uint8(b0));
+        assertEquals(1, uint8(b1));
+        assertEquals(127, uint8(Byte.MAX_VALUE));
+        assertEquals(128, uint8(Byte.MIN_VALUE));
+        assertEquals(255, uint8(bm1));
+        assertEquals(255, uint8((byte)255));
+    }
+
+    @Test
+    public void testUnsignedShortWideningConversions() {
+        short s0 = 0;
+        short s1 = 1;
+        short sm1 = -1;
+        assertEquals(0, uint16(s0));
+        assertEquals(1, uint16(s1));
+        assertEquals(32767, uint16(Short.MAX_VALUE));
+        assertEquals(32768, uint16(Short.MIN_VALUE));
+        assertEquals(65535, uint16(sm1));
+        assertEquals(65535, uint16((short)65535));
+    }
+
+    @Test
+    public void testUnsignedIntWideningConversions() {
+        assertEquals(0, uint32(0));
+        assertEquals(1, uint32(1));
+        assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
+        assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
+        assertEquals(4294967295L, uint32(-1));
+        assertEquals(4294967295L, uint32((int)4294967295L));
+    }
+
+    @Test
+    public void testBytesToInt() {
+        assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
+        assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
+        assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
+        assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
+        assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
+        assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
+
+        assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
+        assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
+        assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
+    }
+
+    @Test
+    public void testUnsignedGetters() {
+      ByteBuffer b = ByteBuffer.allocate(4);
+      b.putInt(0xffff);
+
+      assertEquals(0x0, getUint8(b, 0));
+      assertEquals(0x0, getUint8(b, 1));
+      assertEquals(0xff, getUint8(b, 2));
+      assertEquals(0xff, getUint8(b, 3));
+
+      assertEquals(0x0, getUint16(b, 0));
+      assertEquals(0xffff, getUint16(b, 2));
+
+      b.rewind();
+      b.putInt(0xffffffff);
+      assertEquals(0xffffffffL, getUint32(b, 0));
+    }
+
+    static byte[] bytes(int b1, int b2, int b3, int b4) {
+        return new byte[] {b(b1), b(b2), b(b3), b(b4)};
+    }
+
+    static byte b(int i) {
+        return (byte) i;
+    }
+}
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/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index e527d57..7a1c239 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -29,9 +29,11 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
@@ -53,12 +55,16 @@
 
 import com.android.internal.util.test.BroadcastInterceptingContext;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.Vector;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class TetheringTest {
@@ -81,7 +87,9 @@
     private final TestLooper mLooper = new TestLooper();
     private final String mTestIfname = "test_wlan0";
 
+    private Vector<Intent> mIntents;
     private BroadcastInterceptingContext mServiceContext;
+    private BroadcastReceiver mBroadcastReceiver;
     private Tethering mTethering;
 
     private class MockContext extends BroadcastInterceptingContext {
@@ -100,7 +108,8 @@
         }
     }
 
-    @Before public void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
                 .thenReturn(new String[0]);
@@ -118,10 +127,24 @@
                 .thenReturn(new InterfaceConfiguration());
 
         mServiceContext = new MockContext(mContext);
+        mIntents = new Vector<>();
+        mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                mIntents.addElement(intent);
+            }
+        };
+        mServiceContext.registerReceiver(mBroadcastReceiver,
+                new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
         mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
                                    mLooper.getLooper(), mSystemProperties);
     }
 
+    @After
+    public void tearDown() {
+        mServiceContext.unregisterReceiver(mBroadcastReceiver);
+    }
+
     private void setupForRequiredProvisioning() {
         // Produce some acceptable looking provision app setting if requested.
         when(mResources.getStringArray(
@@ -180,11 +203,26 @@
         mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
+    private void verifyInterfaceServingModeStarted() throws Exception {
+        verify(mNMService, times(1)).listInterfaces();
+        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
+        verify(mNMService, times(1))
+                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).tetherInterface(mTestIfname);
+    }
+
+    private void verifyTetheringBroadcast(String ifname, String whichExtra) {
+        // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
+        final Intent bcast = mIntents.get(0);
+        assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
+        final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
+        assertTrue(ifnames.contains(ifname));
+        mIntents.remove(bcast);
+    }
+
     @Test
     public void workingLocalOnlyHotspot() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-        when(mWifiManager.setWifiApEnabled(any(WifiConfiguration.class), anyBoolean()))
-                .thenReturn(true);
 
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
@@ -193,14 +231,15 @@
         sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        verify(mNMService, times(1)).listInterfaces();
-        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
-        verify(mNMService, times(1))
-                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).tetherInterface(mTestIfname);
+        verifyInterfaceServingModeStarted();
+        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         verify(mNMService, times(1)).startTethering(any(String[].class));
         verifyNoMoreInteractions(mNMService);
+        verify(mWifiManager).updateInterfaceIpState(
+                mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
         // UpstreamNetworkMonitor will be started, and will register two callbacks:
         // a "listen all" and a "track default".
         verify(mConnectivityManager, times(1)).registerNetworkCallback(
@@ -225,6 +264,7 @@
         verify(mNMService, times(1)).stopTethering();
         verify(mNMService, times(1)).setIpForwardingEnabled(false);
         verifyNoMoreInteractions(mNMService);
+        verifyNoMoreInteractions(mWifiManager);
         // Asking for the last error after the per-interface state machine
         // has been reaped yields an unknown interface error.
         assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
@@ -234,13 +274,12 @@
     @Test
     public void workingWifiTethering() throws Exception {
         when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-        when(mWifiManager.setWifiApEnabled(any(WifiConfiguration.class), anyBoolean()))
-                .thenReturn(true);
+        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
         mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).setWifiApEnabled(null, true);
+        verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
@@ -252,14 +291,15 @@
         sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        verify(mNMService, times(1)).listInterfaces();
-        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
-        verify(mNMService, times(1))
-                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).tetherInterface(mTestIfname);
+        verifyInterfaceServingModeStarted();
+        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         verify(mNMService, times(1)).startTethering(any(String[].class));
         verifyNoMoreInteractions(mNMService);
+        verify(mWifiManager).updateInterfaceIpState(
+                mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
         // UpstreamNetworkMonitor will be started, and will register two callbacks:
         // a "listen all" and a "track default".
         verify(mConnectivityManager, times(1)).registerNetworkCallback(
@@ -286,7 +326,7 @@
         // Emulate pressing the WiFi tethering button.
         mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
         mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).setWifiApEnabled(null, false);
+        verify(mWifiManager, times(1)).stopSoftAp();
         verifyNoMoreInteractions(mWifiManager);
         verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
@@ -305,6 +345,7 @@
         verify(mNMService, times(1)).stopTethering();
         verify(mNMService, times(1)).setIpForwardingEnabled(false);
         verifyNoMoreInteractions(mNMService);
+        verifyNoMoreInteractions(mWifiManager);
         // Asking for the last error after the per-interface state machine
         // has been reaped yields an unknown interface error.
         assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index efe6fec..506d9e5 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -27,6 +27,7 @@
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
@@ -42,6 +43,8 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import com.android.internal.net.VpnConfig;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Map;
@@ -101,8 +104,10 @@
     @Override
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         setMockedPackages(mPackages);
+
         when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
         when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
         when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
@@ -258,6 +263,58 @@
     }
 
     @SmallTest
+    public void testLockdownRuleRepeatability() throws Exception {
+        final Vpn vpn = createVpn(primaryUser.id);
+
+        // Given legacy lockdown is already enabled,
+        vpn.setLockdown(true);
+        verify(mNetService, times(1)).setAllowOnlyVpnForUids(
+                eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+        // Enabling legacy lockdown twice should do nothing.
+        vpn.setLockdown(true);
+        verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+
+        // And disabling should remove the rules exactly once.
+        vpn.setLockdown(false);
+        verify(mNetService, times(1)).setAllowOnlyVpnForUids(
+                eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+        // Removing the lockdown again should have no effect.
+        vpn.setLockdown(false);
+        verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+    }
+
+    @SmallTest
+    public void testLockdownRuleReversibility() throws Exception {
+        final Vpn vpn = createVpn(primaryUser.id);
+
+        final UidRange[] entireUser = {
+            UidRange.createForUser(primaryUser.id)
+        };
+        final UidRange[] exceptPkg0 = {
+            new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
+            new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
+        };
+
+        final InOrder order = inOrder(mNetService);
+
+        // Given lockdown is enabled with no package (legacy VPN),
+        vpn.setLockdown(true);
+        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+
+        // When a new VPN package is set the rules should change to cover that package.
+        vpn.prepare(null, PKGS[0]);
+        order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
+        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
+
+        // When that VPN package is unset, everything should be undone again in reverse.
+        vpn.prepare(null, VpnConfig.LEGACY_VPN);
+        order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
+        order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+    }
+
+    @SmallTest
     public void testNotificationShownForAlwaysOnApp() {
         final UserHandle userHandle = UserHandle.of(primaryUser.id);
         final Vpn vpn = createVpn(primaryUser.id);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index caf1a55..a3f33dc 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -32,7 +32,6 @@
 import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
 import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_LOCAL_HOTSPOT;
 import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
 import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
 
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index a84c306..e2ee603 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -802,7 +802,7 @@
     }
 
     struct SymbolComparator {
-        bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) {
+        bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) const {
             return a.symbol.name.value() < b.symbol.name.value();
         }
     };
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index bbf7f41..65c4eb8 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -1080,6 +1080,10 @@
         newRows[i] = image->rows[i + 1];
         memmove(newRows[i], newRows[i] + 4, (W - 2) * 4);
     }
+    delete[] image->rows[0];
+    if (H - 1 > 0) {
+      delete[] image->rows[H - 1];
+    }
     image->rows.swap(newRows);
 
     image->width -= 2;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 69e1029..ad9f9b8 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -125,6 +125,8 @@
 
     void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
 
+    void updateInterfaceIpState(String ifaceName, int mode);
+
     boolean startSoftAp(in WifiConfiguration wifiConfig);
 
     boolean stopSoftAp();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ae8a224..b7fe9c7 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -20,7 +20,6 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.net.ConnectivityManager;
@@ -46,9 +45,9 @@
 import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
-import java.util.Collections;
 
 /**
  * This class provides the primary API for managing all aspects of Wi-Fi
@@ -446,6 +445,35 @@
      *  @hide
      */
     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
+
+    /**
+     * Interface IP mode for configuration error.
+     *
+     * @see updateInterfaceIpState(String, int)
+     *
+     * @hide
+     */
+    public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
+
+    /**
+     * Interface IP mode for tethering.
+     *
+     * @see updateInterfaceIpState(String, int)
+     *
+     * @hide
+     */
+    public static final int IFACE_IP_MODE_TETHERED = 1;
+
+    /**
+     * Interface IP mode for Local Only Hotspot.
+     *
+     * @see updateInterfaceIpState(String, int)
+     *
+     * @hide
+     */
+    public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
+
+
     /**
      * Broadcast intent action indicating that a connection to the supplicant has
      * been established (and it is now possible
@@ -1718,6 +1746,26 @@
     }
 
     /**
+     * Call allowing ConnectivityService to update WifiService with interface mode changes.
+     *
+     * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
+     *                             {@link IFACE_IP_MODE_LOCAL_ONLY},
+     *                             {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
+     *
+     * @param ifaceName String name of the updated interface
+     * @param mode int representing the new mode
+     *
+     * @hide
+     */
+    public void updateInterfaceIpState(String ifaceName, int mode) {
+        try {
+            mService.updateInterfaceIpState(ifaceName, mode);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Start SoftAp mode with the specified configuration.
      * Note that starting in access point mode disables station
      * mode operation
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");
+        }
+    }
 }