Merge "Fix dead lock in Tethering state machine"
diff --git a/Android.mk b/Android.mk
index a798a31..4e1479a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -435,6 +435,7 @@
 	telephony/java/com/android/ims/internal/IImsEcbm.aidl \
 	telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
         telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
+        telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl \
         telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
 	telephony/java/com/android/ims/internal/IImsService.aidl \
 	telephony/java/com/android/ims/internal/IImsServiceController.aidl \
@@ -513,6 +514,7 @@
 
 LOCAL_MODULE := framework
 
+LOCAL_DX_FLAGS := --core-library --multi-dex
 LOCAL_JACK_FLAGS := --multi-dex native
 
 LOCAL_RMTYPEDEFS := true
@@ -1348,6 +1350,8 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := ext
 
+LOCAL_DX_FLAGS := --core-library
+
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
     LOCAL_JACK_ENABLED := incremental
diff --git a/api/current.txt b/api/current.txt
index 42275de..159b025 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8553,6 +8553,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
     field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -24629,9 +24630,10 @@
     field public java.util.BitSet allowedProtocols;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
+    field public boolean isHomeProviderNetwork;
     field public int networkId;
     field public java.lang.String preSharedKey;
-    field public int priority;
+    field public deprecated int priority;
     field public java.lang.String providerFriendlyName;
     field public long[] roamingConsortiumIds;
     field public int status;
@@ -24736,11 +24738,14 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
+    field public static final int AKA = 6; // 0x6
+    field public static final int AKA_PRIME = 7; // 0x7
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int PAP = 1; // 0x1
+    field public static final int SIM = 5; // 0x5
   }
 
   public class WifiInfo implements android.os.Parcelable {
@@ -24763,6 +24768,7 @@
 
   public class WifiManager {
     method public int addNetwork(android.net.wifi.WifiConfiguration);
+    method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method public static int calculateSignalLevel(int, int);
     method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
@@ -24775,6 +24781,7 @@
     method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
+    method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -24785,12 +24792,13 @@
     method public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
     method public boolean isWifiEnabled();
-    method public boolean pingSupplicant();
+    method public deprecated boolean pingSupplicant();
     method public void queryPasspointIcon(long, java.lang.String);
     method public boolean reassociate();
     method public boolean reconnect();
     method public boolean removeNetwork(int);
-    method public boolean saveConfiguration();
+    method public boolean removePasspointConfiguration(java.lang.String);
+    method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -24908,8 +24916,6 @@
   public class DiscoverySession {
     method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
     method public void destroy();
-    method public static int getMaxSendRetryCount();
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
     method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
   }
 
@@ -25004,6 +25010,241 @@
 
 }
 
+package android.net.wifi.hotspot2 {
+
+  public final class ConfigParser {
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+  }
+
+  public final class PasspointConfiguration implements android.os.Parcelable {
+    ctor public PasspointConfiguration();
+    ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+    method public int describeContents();
+    method public android.net.wifi.hotspot2.pps.Credential getCredential();
+    method public int getCredentialPriority();
+    method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+    method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+    method public long getSubscriptionCreationTimeInMs();
+    method public long getSubscriptionExpirationTimeInMs();
+    method public java.lang.String getSubscriptionType();
+    method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+    method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+    method public int getUpdateIdentifier();
+    method public long getUsageLimitDataLimit();
+    method public long getUsageLimitStartTimeInMs();
+    method public long getUsageLimitTimeLimitInMinutes();
+    method public long getUsageLimitUsageTimePeriodInMinutes();
+    method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+    method public void setCredentialPriority(int);
+    method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+    method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+    method public void setSubscriptionCreationTimeInMs(long);
+    method public void setSubscriptionExpirationTimeInMs(long);
+    method public void setSubscriptionType(java.lang.String);
+    method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+    method public void setUpdateIdentifier(int);
+    method public void setUsageLimitDataLimit(long);
+    method public void setUsageLimitStartTimeInMs(long);
+    method public void setUsageLimitTimeLimitInMinutes(long);
+    method public void setUsageLimitUsageTimePeriodInMinutes(long);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+  }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+  public final class PpsMoParser {
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+  }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+  public final class Credential implements android.os.Parcelable {
+    ctor public Credential();
+    ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+    method public int describeContents();
+    method public java.security.cert.X509Certificate getCaCertificate();
+    method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+    method public boolean getCheckAaaServerCertStatus();
+    method public java.security.cert.X509Certificate[] getClientCertificateChain();
+    method public java.security.PrivateKey getClientPrivateKey();
+    method public long getCreationTimeInMs();
+    method public long getExpirationTimeInMs();
+    method public java.lang.String getRealm();
+    method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+    method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+    method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+    method public void setCheckAaaServerCertStatus(boolean);
+    method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+    method public void setClientPrivateKey(java.security.PrivateKey);
+    method public void setCreationTimeInMs(long);
+    method public void setExpirationTimeInMs(long);
+    method public void setRealm(java.lang.String);
+    method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+    method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+  }
+
+  public static final class Credential.CertificateCredential implements android.os.Parcelable {
+    ctor public Credential.CertificateCredential();
+    ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+    method public int describeContents();
+    method public byte[] getCertSha256Fingerprint();
+    method public java.lang.String getCertType();
+    method public void setCertSha256Fingerprint(byte[]);
+    method public void setCertType(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+  }
+
+  public static final class Credential.SimCredential implements android.os.Parcelable {
+    ctor public Credential.SimCredential();
+    ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+    method public int describeContents();
+    method public int getEapType();
+    method public java.lang.String getImsi();
+    method public void setEapType(int);
+    method public void setImsi(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+  }
+
+  public static final class Credential.UserCredential implements android.os.Parcelable {
+    ctor public Credential.UserCredential();
+    ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+    method public int describeContents();
+    method public boolean getAbleToShare();
+    method public int getEapType();
+    method public boolean getMachineManaged();
+    method public java.lang.String getNonEapInnerMethod();
+    method public java.lang.String getPassword();
+    method public java.lang.String getSoftTokenApp();
+    method public java.lang.String getUsername();
+    method public void setAbleToShare(boolean);
+    method public void setEapType(int);
+    method public void setMachineManaged(boolean);
+    method public void setNonEapInnerMethod(java.lang.String);
+    method public void setPassword(java.lang.String);
+    method public void setSoftTokenApp(java.lang.String);
+    method public void setUsername(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+  }
+
+  public final class HomeSp implements android.os.Parcelable {
+    ctor public HomeSp();
+    ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+    method public int describeContents();
+    method public java.lang.String getFqdn();
+    method public java.lang.String getFriendlyName();
+    method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+    method public java.lang.String getIconUrl();
+    method public long[] getMatchAllOis();
+    method public long[] getMatchAnyOis();
+    method public java.lang.String[] getOtherHomePartners();
+    method public long[] getRoamingConsortiumOis();
+    method public void setFqdn(java.lang.String);
+    method public void setFriendlyName(java.lang.String);
+    method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+    method public void setIconUrl(java.lang.String);
+    method public void setMatchAllOis(long[]);
+    method public void setMatchAnyOis(long[]);
+    method public void setOtherHomePartners(java.lang.String[]);
+    method public void setRoamingConsortiumOis(long[]);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+  }
+
+  public final class Policy implements android.os.Parcelable {
+    ctor public Policy();
+    ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+    method public int describeContents();
+    method public java.lang.String[] getExcludedSsidList();
+    method public int getMaximumBssLoadValue();
+    method public long getMinHomeDownlinkBandwidth();
+    method public long getMinHomeUplinkBandwidth();
+    method public long getMinRoamingDownlinkBandwidth();
+    method public long getMinRoamingUplinkBandwidth();
+    method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+    method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+    method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+    method public void setExcludedSsidList(java.lang.String[]);
+    method public void setMaximumBssLoadValue(int);
+    method public void setMinHomeDownlinkBandwidth(long);
+    method public void setMinHomeUplinkBandwidth(long);
+    method public void setMinRoamingDownlinkBandwidth(long);
+    method public void setMinRoamingUplinkBandwidth(long);
+    method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+    method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+  }
+
+  public static final class Policy.RoamingPartner implements android.os.Parcelable {
+    ctor public Policy.RoamingPartner();
+    ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+    method public int describeContents();
+    method public java.lang.String getCountries();
+    method public java.lang.String getFqdn();
+    method public boolean getFqdnExactMatch();
+    method public int getPriority();
+    method public void setCountries(java.lang.String);
+    method public void setFqdn(java.lang.String);
+    method public void setFqdnExactMatch(boolean);
+    method public void setPriority(int);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+  }
+
+  public final class UpdateParameter implements android.os.Parcelable {
+    ctor public UpdateParameter();
+    ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public int describeContents();
+    method public java.lang.String getBase64EncodedPassword();
+    method public java.lang.String getRestriction();
+    method public java.lang.String getServerUri();
+    method public byte[] getTrustRootCertSha256Fingerprint();
+    method public java.lang.String getTrustRootCertUrl();
+    method public long getUpdateIntervalInMinutes();
+    method public java.lang.String getUpdateMethod();
+    method public java.lang.String getUsername();
+    method public void setBase64EncodedPassword(java.lang.String);
+    method public void setRestriction(java.lang.String);
+    method public void setServerUri(java.lang.String);
+    method public void setTrustRootCertSha256Fingerprint(byte[]);
+    method public void setTrustRootCertUrl(java.lang.String);
+    method public void setUpdateIntervalInMinutes(long);
+    method public void setUpdateMethod(java.lang.String);
+    method public void setUsername(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+    field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+    field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+    field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+    field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+    field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+    field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -36339,9 +36580,11 @@
     method public android.telecom.Call.Details getDetails();
     method public android.telecom.Call getParent();
     method public java.lang.String getRemainingPostDialSequence();
+    method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
     method public void hold();
+    method public boolean isRttActive();
     method public void mergeConference();
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
@@ -36353,9 +36596,12 @@
     method public void reject(boolean, java.lang.String);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
+    method public void respondToRttRequest(int, boolean);
     method public void sendCallEvent(java.lang.String, android.os.Bundle);
+    method public void sendRttRequest();
     method public void splitFromConference();
     method public void stopDtmfTone();
+    method public void stopRtt();
     method public void swapConference();
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36382,6 +36628,9 @@
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
+    method public void onRttModeChanged(android.telecom.Call, int);
+    method public void onRttRequest(android.telecom.Call, int);
+    method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
   }
@@ -36435,6 +36684,16 @@
     field public static final int PROPERTY_WIFI = 8; // 0x8
   }
 
+  public static final class Call.RttCall {
+    method public int getRttAudioMode();
+    method public java.lang.String read();
+    method public void setRttMode(int);
+    method public void write(java.lang.String) throws java.io.IOException;
+    field public static final int RTT_MODE_FULL = 1; // 0x1
+    field public static final int RTT_MODE_HCO = 2; // 0x2
+    field public static final int RTT_MODE_VCO = 3; // 0x3
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
@@ -36654,6 +36913,7 @@
     method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void setCallDataUsage(long);
     field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
     field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -36805,6 +37065,7 @@
     field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_RTT = 4096; // 0x1000
     field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37017,6 +37278,7 @@
     field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -37170,6 +37432,7 @@
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -38494,7 +38757,7 @@
 
 package android.test.suitebuilder {
 
-  public class TestMethod {
+  public deprecated class TestMethod {
     ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(junit.framework.TestCase);
@@ -38505,7 +38768,7 @@
     method public java.lang.String getName();
   }
 
-  public class TestSuiteBuilder {
+  public deprecated class TestSuiteBuilder {
     ctor public TestSuiteBuilder(java.lang.Class);
     ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
     method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -38518,7 +38781,7 @@
     method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
   }
 
-  public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+  public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
     ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
     method public void testSuiteConstructionFailed();
   }
@@ -48888,7 +49151,7 @@
 
 package com.android.internal.util {
 
-  public abstract interface Predicate<T> {
+  public abstract deprecated interface Predicate<T> {
     method public abstract boolean apply(T);
   }
 
@@ -49026,6 +49289,8 @@
     field public static final int OP_INT_TO_FLOAT = 130; // 0x82
     field public static final int OP_INT_TO_LONG = 129; // 0x81
     field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+    field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+    field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
     field public static final int OP_INVOKE_DIRECT = 112; // 0x70
     field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
     field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -49033,6 +49298,8 @@
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
     field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
     field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+    field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+    field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_STATIC = 113; // 0x71
     field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -49214,7 +49481,7 @@
     method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
-  public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+  public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
   }
 
@@ -50432,6 +50699,13 @@
     field public static final java.lang.Class<java.lang.Boolean> TYPE;
   }
 
+  public class BootstrapMethodError extends java.lang.LinkageError {
+    ctor public BootstrapMethodError();
+    ctor public BootstrapMethodError(java.lang.String);
+    ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+    ctor public BootstrapMethodError(java.lang.Throwable);
+  }
+
   public final class Byte extends java.lang.Number implements java.lang.Comparable {
     ctor public Byte(byte);
     ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -52318,6 +52592,21 @@
 
 package java.lang.invoke {
 
+  public abstract class CallSite {
+    method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+    method public abstract java.lang.invoke.MethodHandle getTarget();
+    method public abstract void setTarget(java.lang.invoke.MethodHandle);
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public class ConstantCallSite extends java.lang.invoke.CallSite {
+    ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+    ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public final void setTarget(java.lang.invoke.MethodHandle);
+  }
+
   public class LambdaConversionException extends java.lang.Exception {
     ctor public LambdaConversionException();
     ctor public LambdaConversionException(java.lang.String);
@@ -52327,12 +52616,15 @@
   }
 
   public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
     method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
     method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
     method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
     method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
     method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
@@ -52366,17 +52658,23 @@
     method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
     method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
   }
 
@@ -52393,7 +52691,7 @@
     method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
-    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -52436,6 +52734,22 @@
     method public java.lang.invoke.MethodType wrap();
   }
 
+  public class MutableCallSite extends java.lang.invoke.CallSite {
+    ctor public MutableCallSite(java.lang.invoke.MethodType);
+    ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public void setTarget(java.lang.invoke.MethodHandle);
+  }
+
+  public class VolatileCallSite extends java.lang.invoke.CallSite {
+    ctor public VolatileCallSite(java.lang.invoke.MethodType);
+    ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public void setTarget(java.lang.invoke.MethodHandle);
+  }
+
   public class WrongMethodTypeException extends java.lang.RuntimeException {
     ctor public WrongMethodTypeException();
     ctor public WrongMethodTypeException(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6ebbee2..deeb679 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8895,6 +8895,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
     field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -26979,6 +26980,7 @@
     field public int creatorUid;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
+    field public boolean isHomeProviderNetwork;
     field public java.lang.String lastUpdateName;
     field public int lastUpdateUid;
     field public boolean meteredHint;
@@ -26987,7 +26989,7 @@
     field public int numScorerOverride;
     field public int numScorerOverrideAndSwitchedNetwork;
     field public java.lang.String preSharedKey;
-    field public int priority;
+    field public deprecated int priority;
     field public java.lang.String providerFriendlyName;
     field public long[] roamingConsortiumIds;
     field public int status;
@@ -27109,11 +27111,14 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
+    field public static final int AKA = 6; // 0x6
+    field public static final int AKA_PRIME = 7; // 0x7
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int PAP = 1; // 0x1
+    field public static final int SIM = 5; // 0x5
   }
 
   public class WifiInfo implements android.os.Parcelable {
@@ -27136,6 +27141,7 @@
 
   public class WifiManager {
     method public int addNetwork(android.net.wifi.WifiConfiguration);
+    method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method public static int calculateSignalLevel(int, int);
     method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
@@ -27151,6 +27157,7 @@
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
     method public android.net.DhcpInfo getDhcpInfo();
+    method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
@@ -27169,12 +27176,13 @@
     method public boolean isWifiApEnabled();
     method public boolean isWifiEnabled();
     method public boolean isWifiScannerSupported();
-    method public boolean pingSupplicant();
+    method public deprecated boolean pingSupplicant();
     method public void queryPasspointIcon(long, java.lang.String);
     method public boolean reassociate();
     method public boolean reconnect();
     method public boolean removeNetwork(int);
-    method public boolean saveConfiguration();
+    method public boolean removePasspointConfiguration(java.lang.String);
+    method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -27461,8 +27469,6 @@
   public class DiscoverySession {
     method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
     method public void destroy();
-    method public static int getMaxSendRetryCount();
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
     method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
   }
 
@@ -27557,6 +27563,241 @@
 
 }
 
+package android.net.wifi.hotspot2 {
+
+  public final class ConfigParser {
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+  }
+
+  public final class PasspointConfiguration implements android.os.Parcelable {
+    ctor public PasspointConfiguration();
+    ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+    method public int describeContents();
+    method public android.net.wifi.hotspot2.pps.Credential getCredential();
+    method public int getCredentialPriority();
+    method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+    method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+    method public long getSubscriptionCreationTimeInMs();
+    method public long getSubscriptionExpirationTimeInMs();
+    method public java.lang.String getSubscriptionType();
+    method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+    method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+    method public int getUpdateIdentifier();
+    method public long getUsageLimitDataLimit();
+    method public long getUsageLimitStartTimeInMs();
+    method public long getUsageLimitTimeLimitInMinutes();
+    method public long getUsageLimitUsageTimePeriodInMinutes();
+    method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+    method public void setCredentialPriority(int);
+    method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+    method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+    method public void setSubscriptionCreationTimeInMs(long);
+    method public void setSubscriptionExpirationTimeInMs(long);
+    method public void setSubscriptionType(java.lang.String);
+    method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+    method public void setUpdateIdentifier(int);
+    method public void setUsageLimitDataLimit(long);
+    method public void setUsageLimitStartTimeInMs(long);
+    method public void setUsageLimitTimeLimitInMinutes(long);
+    method public void setUsageLimitUsageTimePeriodInMinutes(long);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+  }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+  public final class PpsMoParser {
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+  }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+  public final class Credential implements android.os.Parcelable {
+    ctor public Credential();
+    ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+    method public int describeContents();
+    method public java.security.cert.X509Certificate getCaCertificate();
+    method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+    method public boolean getCheckAaaServerCertStatus();
+    method public java.security.cert.X509Certificate[] getClientCertificateChain();
+    method public java.security.PrivateKey getClientPrivateKey();
+    method public long getCreationTimeInMs();
+    method public long getExpirationTimeInMs();
+    method public java.lang.String getRealm();
+    method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+    method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+    method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+    method public void setCheckAaaServerCertStatus(boolean);
+    method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+    method public void setClientPrivateKey(java.security.PrivateKey);
+    method public void setCreationTimeInMs(long);
+    method public void setExpirationTimeInMs(long);
+    method public void setRealm(java.lang.String);
+    method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+    method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+  }
+
+  public static final class Credential.CertificateCredential implements android.os.Parcelable {
+    ctor public Credential.CertificateCredential();
+    ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+    method public int describeContents();
+    method public byte[] getCertSha256Fingerprint();
+    method public java.lang.String getCertType();
+    method public void setCertSha256Fingerprint(byte[]);
+    method public void setCertType(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+  }
+
+  public static final class Credential.SimCredential implements android.os.Parcelable {
+    ctor public Credential.SimCredential();
+    ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+    method public int describeContents();
+    method public int getEapType();
+    method public java.lang.String getImsi();
+    method public void setEapType(int);
+    method public void setImsi(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+  }
+
+  public static final class Credential.UserCredential implements android.os.Parcelable {
+    ctor public Credential.UserCredential();
+    ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+    method public int describeContents();
+    method public boolean getAbleToShare();
+    method public int getEapType();
+    method public boolean getMachineManaged();
+    method public java.lang.String getNonEapInnerMethod();
+    method public java.lang.String getPassword();
+    method public java.lang.String getSoftTokenApp();
+    method public java.lang.String getUsername();
+    method public void setAbleToShare(boolean);
+    method public void setEapType(int);
+    method public void setMachineManaged(boolean);
+    method public void setNonEapInnerMethod(java.lang.String);
+    method public void setPassword(java.lang.String);
+    method public void setSoftTokenApp(java.lang.String);
+    method public void setUsername(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+  }
+
+  public final class HomeSp implements android.os.Parcelable {
+    ctor public HomeSp();
+    ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+    method public int describeContents();
+    method public java.lang.String getFqdn();
+    method public java.lang.String getFriendlyName();
+    method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+    method public java.lang.String getIconUrl();
+    method public long[] getMatchAllOis();
+    method public long[] getMatchAnyOis();
+    method public java.lang.String[] getOtherHomePartners();
+    method public long[] getRoamingConsortiumOis();
+    method public void setFqdn(java.lang.String);
+    method public void setFriendlyName(java.lang.String);
+    method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+    method public void setIconUrl(java.lang.String);
+    method public void setMatchAllOis(long[]);
+    method public void setMatchAnyOis(long[]);
+    method public void setOtherHomePartners(java.lang.String[]);
+    method public void setRoamingConsortiumOis(long[]);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+  }
+
+  public final class Policy implements android.os.Parcelable {
+    ctor public Policy();
+    ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+    method public int describeContents();
+    method public java.lang.String[] getExcludedSsidList();
+    method public int getMaximumBssLoadValue();
+    method public long getMinHomeDownlinkBandwidth();
+    method public long getMinHomeUplinkBandwidth();
+    method public long getMinRoamingDownlinkBandwidth();
+    method public long getMinRoamingUplinkBandwidth();
+    method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+    method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+    method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+    method public void setExcludedSsidList(java.lang.String[]);
+    method public void setMaximumBssLoadValue(int);
+    method public void setMinHomeDownlinkBandwidth(long);
+    method public void setMinHomeUplinkBandwidth(long);
+    method public void setMinRoamingDownlinkBandwidth(long);
+    method public void setMinRoamingUplinkBandwidth(long);
+    method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+    method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+  }
+
+  public static final class Policy.RoamingPartner implements android.os.Parcelable {
+    ctor public Policy.RoamingPartner();
+    ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+    method public int describeContents();
+    method public java.lang.String getCountries();
+    method public java.lang.String getFqdn();
+    method public boolean getFqdnExactMatch();
+    method public int getPriority();
+    method public void setCountries(java.lang.String);
+    method public void setFqdn(java.lang.String);
+    method public void setFqdnExactMatch(boolean);
+    method public void setPriority(int);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+  }
+
+  public final class UpdateParameter implements android.os.Parcelable {
+    ctor public UpdateParameter();
+    ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public int describeContents();
+    method public java.lang.String getBase64EncodedPassword();
+    method public java.lang.String getRestriction();
+    method public java.lang.String getServerUri();
+    method public byte[] getTrustRootCertSha256Fingerprint();
+    method public java.lang.String getTrustRootCertUrl();
+    method public long getUpdateIntervalInMinutes();
+    method public java.lang.String getUpdateMethod();
+    method public java.lang.String getUsername();
+    method public void setBase64EncodedPassword(java.lang.String);
+    method public void setRestriction(java.lang.String);
+    method public void setServerUri(java.lang.String);
+    method public void setTrustRootCertSha256Fingerprint(byte[]);
+    method public void setTrustRootCertUrl(java.lang.String);
+    method public void setUpdateIntervalInMinutes(long);
+    method public void setUpdateMethod(java.lang.String);
+    method public void setUsername(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+    field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+    field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+    field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+    field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+    field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+    field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -39306,9 +39547,11 @@
     method public android.telecom.Call.Details getDetails();
     method public android.telecom.Call getParent();
     method public java.lang.String getRemainingPostDialSequence();
+    method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
     method public void hold();
+    method public boolean isRttActive();
     method public void mergeConference();
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
@@ -39321,9 +39564,12 @@
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
     method public deprecated void removeListener(android.telecom.Call.Listener);
+    method public void respondToRttRequest(int, boolean);
     method public void sendCallEvent(java.lang.String, android.os.Bundle);
+    method public void sendRttRequest();
     method public void splitFromConference();
     method public void stopDtmfTone();
+    method public void stopRtt();
     method public void swapConference();
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
@@ -39351,6 +39597,9 @@
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
+    method public void onRttModeChanged(android.telecom.Call, int);
+    method public void onRttRequest(android.telecom.Call, int);
+    method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
   }
@@ -39408,6 +39657,16 @@
     ctor public Call.Listener();
   }
 
+  public static final class Call.RttCall {
+    method public int getRttAudioMode();
+    method public java.lang.String read();
+    method public void setRttMode(int);
+    method public void write(java.lang.String) throws java.io.IOException;
+    field public static final int RTT_MODE_FULL = 1; // 0x1
+    field public static final int RTT_MODE_HCO = 2; // 0x2
+    field public static final int RTT_MODE_VCO = 3; // 0x3
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
@@ -39634,6 +39893,7 @@
     method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void setCallDataUsage(long);
     field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
     field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -39909,6 +40169,7 @@
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_RTT = 4096; // 0x1000
     field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -40185,6 +40446,7 @@
     field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -40340,6 +40602,7 @@
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -41758,7 +42021,7 @@
 
 package android.test.suitebuilder {
 
-  public class TestMethod {
+  public deprecated class TestMethod {
     ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(junit.framework.TestCase);
@@ -41769,7 +42032,7 @@
     method public java.lang.String getName();
   }
 
-  public class TestSuiteBuilder {
+  public deprecated class TestSuiteBuilder {
     ctor public TestSuiteBuilder(java.lang.Class);
     ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
     method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -41782,7 +42045,7 @@
     method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
   }
 
-  public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+  public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
     ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
     method public void testSuiteConstructionFailed();
   }
@@ -52509,7 +52772,7 @@
 
 package com.android.internal.util {
 
-  public abstract interface Predicate<T> {
+  public abstract deprecated interface Predicate<T> {
     method public abstract boolean apply(T);
   }
 
@@ -52647,6 +52910,8 @@
     field public static final int OP_INT_TO_FLOAT = 130; // 0x82
     field public static final int OP_INT_TO_LONG = 129; // 0x81
     field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+    field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+    field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
     field public static final int OP_INVOKE_DIRECT = 112; // 0x70
     field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
     field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -52654,6 +52919,8 @@
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
     field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
     field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+    field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+    field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_STATIC = 113; // 0x71
     field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -52835,7 +53102,7 @@
     method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
-  public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+  public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
   }
 
@@ -54053,6 +54320,13 @@
     field public static final java.lang.Class<java.lang.Boolean> TYPE;
   }
 
+  public class BootstrapMethodError extends java.lang.LinkageError {
+    ctor public BootstrapMethodError();
+    ctor public BootstrapMethodError(java.lang.String);
+    ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+    ctor public BootstrapMethodError(java.lang.Throwable);
+  }
+
   public final class Byte extends java.lang.Number implements java.lang.Comparable {
     ctor public Byte(byte);
     ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -55939,6 +56213,21 @@
 
 package java.lang.invoke {
 
+  public abstract class CallSite {
+    method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+    method public abstract java.lang.invoke.MethodHandle getTarget();
+    method public abstract void setTarget(java.lang.invoke.MethodHandle);
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public class ConstantCallSite extends java.lang.invoke.CallSite {
+    ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+    ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public final void setTarget(java.lang.invoke.MethodHandle);
+  }
+
   public class LambdaConversionException extends java.lang.Exception {
     ctor public LambdaConversionException();
     ctor public LambdaConversionException(java.lang.String);
@@ -55948,12 +56237,15 @@
   }
 
   public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
     method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
     method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
     method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
     method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
     method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
@@ -55987,17 +56279,23 @@
     method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
     method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
   }
 
@@ -56014,7 +56312,7 @@
     method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
-    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -56057,6 +56355,22 @@
     method public java.lang.invoke.MethodType wrap();
   }
 
+  public class MutableCallSite extends java.lang.invoke.CallSite {
+    ctor public MutableCallSite(java.lang.invoke.MethodType);
+    ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public void setTarget(java.lang.invoke.MethodHandle);
+  }
+
+  public class VolatileCallSite extends java.lang.invoke.CallSite {
+    ctor public VolatileCallSite(java.lang.invoke.MethodType);
+    ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public void setTarget(java.lang.invoke.MethodHandle);
+  }
+
   public class WrongMethodTypeException extends java.lang.RuntimeException {
     ctor public WrongMethodTypeException();
     ctor public WrongMethodTypeException(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 40085a2..694415f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8565,6 +8565,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
     field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -24702,9 +24703,10 @@
     field public java.util.BitSet allowedProtocols;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
+    field public boolean isHomeProviderNetwork;
     field public int networkId;
     field public java.lang.String preSharedKey;
-    field public int priority;
+    field public deprecated int priority;
     field public java.lang.String providerFriendlyName;
     field public long[] roamingConsortiumIds;
     field public int status;
@@ -24809,11 +24811,14 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
+    field public static final int AKA = 6; // 0x6
+    field public static final int AKA_PRIME = 7; // 0x7
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int PAP = 1; // 0x1
+    field public static final int SIM = 5; // 0x5
   }
 
   public class WifiInfo implements android.os.Parcelable {
@@ -24836,6 +24841,7 @@
 
   public class WifiManager {
     method public int addNetwork(android.net.wifi.WifiConfiguration);
+    method public boolean addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method public static int calculateSignalLevel(int, int);
     method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
@@ -24848,6 +24854,7 @@
     method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
+    method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -24858,12 +24865,13 @@
     method public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
     method public boolean isWifiEnabled();
-    method public boolean pingSupplicant();
+    method public deprecated boolean pingSupplicant();
     method public void queryPasspointIcon(long, java.lang.String);
     method public boolean reassociate();
     method public boolean reconnect();
     method public boolean removeNetwork(int);
-    method public boolean saveConfiguration();
+    method public boolean removePasspointConfiguration(java.lang.String);
+    method public deprecated boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -24981,8 +24989,6 @@
   public class DiscoverySession {
     method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
     method public void destroy();
-    method public static int getMaxSendRetryCount();
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
     method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
   }
 
@@ -25077,6 +25083,241 @@
 
 }
 
+package android.net.wifi.hotspot2 {
+
+  public final class ConfigParser {
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+  }
+
+  public final class PasspointConfiguration implements android.os.Parcelable {
+    ctor public PasspointConfiguration();
+    ctor public PasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
+    method public int describeContents();
+    method public android.net.wifi.hotspot2.pps.Credential getCredential();
+    method public int getCredentialPriority();
+    method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+    method public android.net.wifi.hotspot2.pps.Policy getPolicy();
+    method public long getSubscriptionCreationTimeInMs();
+    method public long getSubscriptionExpirationTimeInMs();
+    method public java.lang.String getSubscriptionType();
+    method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
+    method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
+    method public int getUpdateIdentifier();
+    method public long getUsageLimitDataLimit();
+    method public long getUsageLimitStartTimeInMs();
+    method public long getUsageLimitTimeLimitInMinutes();
+    method public long getUsageLimitUsageTimePeriodInMinutes();
+    method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
+    method public void setCredentialPriority(int);
+    method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+    method public void setPolicy(android.net.wifi.hotspot2.pps.Policy);
+    method public void setSubscriptionCreationTimeInMs(long);
+    method public void setSubscriptionExpirationTimeInMs(long);
+    method public void setSubscriptionType(java.lang.String);
+    method public void setSubscriptionUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public void setTrustRootCertList(java.util.Map<java.lang.String, byte[]>);
+    method public void setUpdateIdentifier(int);
+    method public void setUsageLimitDataLimit(long);
+    method public void setUsageLimitStartTimeInMs(long);
+    method public void setUsageLimitTimeLimitInMinutes(long);
+    method public void setUsageLimitUsageTimePeriodInMinutes(long);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.PasspointConfiguration> CREATOR;
+  }
+
+}
+
+package android.net.wifi.hotspot2.omadm {
+
+  public final class PpsMoParser {
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+  }
+
+}
+
+package android.net.wifi.hotspot2.pps {
+
+  public final class Credential implements android.os.Parcelable {
+    ctor public Credential();
+    ctor public Credential(android.net.wifi.hotspot2.pps.Credential);
+    method public int describeContents();
+    method public java.security.cert.X509Certificate getCaCertificate();
+    method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
+    method public boolean getCheckAaaServerCertStatus();
+    method public java.security.cert.X509Certificate[] getClientCertificateChain();
+    method public java.security.PrivateKey getClientPrivateKey();
+    method public long getCreationTimeInMs();
+    method public long getExpirationTimeInMs();
+    method public java.lang.String getRealm();
+    method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
+    method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
+    method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+    method public void setCheckAaaServerCertStatus(boolean);
+    method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
+    method public void setClientPrivateKey(java.security.PrivateKey);
+    method public void setCreationTimeInMs(long);
+    method public void setExpirationTimeInMs(long);
+    method public void setRealm(java.lang.String);
+    method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+    method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential> CREATOR;
+  }
+
+  public static final class Credential.CertificateCredential implements android.os.Parcelable {
+    ctor public Credential.CertificateCredential();
+    ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
+    method public int describeContents();
+    method public byte[] getCertSha256Fingerprint();
+    method public java.lang.String getCertType();
+    method public void setCertSha256Fingerprint(byte[]);
+    method public void setCertType(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
+  }
+
+  public static final class Credential.SimCredential implements android.os.Parcelable {
+    ctor public Credential.SimCredential();
+    ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
+    method public int describeContents();
+    method public int getEapType();
+    method public java.lang.String getImsi();
+    method public void setEapType(int);
+    method public void setImsi(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
+  }
+
+  public static final class Credential.UserCredential implements android.os.Parcelable {
+    ctor public Credential.UserCredential();
+    ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
+    method public int describeContents();
+    method public boolean getAbleToShare();
+    method public int getEapType();
+    method public boolean getMachineManaged();
+    method public java.lang.String getNonEapInnerMethod();
+    method public java.lang.String getPassword();
+    method public java.lang.String getSoftTokenApp();
+    method public java.lang.String getUsername();
+    method public void setAbleToShare(boolean);
+    method public void setEapType(int);
+    method public void setMachineManaged(boolean);
+    method public void setNonEapInnerMethod(java.lang.String);
+    method public void setPassword(java.lang.String);
+    method public void setSoftTokenApp(java.lang.String);
+    method public void setUsername(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
+  }
+
+  public final class HomeSp implements android.os.Parcelable {
+    ctor public HomeSp();
+    ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
+    method public int describeContents();
+    method public java.lang.String getFqdn();
+    method public java.lang.String getFriendlyName();
+    method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
+    method public java.lang.String getIconUrl();
+    method public long[] getMatchAllOis();
+    method public long[] getMatchAnyOis();
+    method public java.lang.String[] getOtherHomePartners();
+    method public long[] getRoamingConsortiumOis();
+    method public void setFqdn(java.lang.String);
+    method public void setFriendlyName(java.lang.String);
+    method public void setHomeNetworkIds(java.util.Map<java.lang.String, java.lang.Long>);
+    method public void setIconUrl(java.lang.String);
+    method public void setMatchAllOis(long[]);
+    method public void setMatchAnyOis(long[]);
+    method public void setOtherHomePartners(java.lang.String[]);
+    method public void setRoamingConsortiumOis(long[]);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
+  }
+
+  public final class Policy implements android.os.Parcelable {
+    ctor public Policy();
+    ctor public Policy(android.net.wifi.hotspot2.pps.Policy);
+    method public int describeContents();
+    method public java.lang.String[] getExcludedSsidList();
+    method public int getMaximumBssLoadValue();
+    method public long getMinHomeDownlinkBandwidth();
+    method public long getMinHomeUplinkBandwidth();
+    method public long getMinRoamingDownlinkBandwidth();
+    method public long getMinRoamingUplinkBandwidth();
+    method public android.net.wifi.hotspot2.pps.UpdateParameter getPolicyUpdate();
+    method public java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> getPreferredRoamingPartnerList();
+    method public java.util.Map<java.lang.Integer, java.lang.String> getRequiredProtoPortMap();
+    method public void setExcludedSsidList(java.lang.String[]);
+    method public void setMaximumBssLoadValue(int);
+    method public void setMinHomeDownlinkBandwidth(long);
+    method public void setMinHomeUplinkBandwidth(long);
+    method public void setMinRoamingDownlinkBandwidth(long);
+    method public void setMinRoamingUplinkBandwidth(long);
+    method public void setPolicyUpdate(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public void setPreferredRoamingPartnerList(java.util.List<android.net.wifi.hotspot2.pps.Policy.RoamingPartner>);
+    method public void setRequiredProtoPortMap(java.util.Map<java.lang.Integer, java.lang.String>);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy> CREATOR;
+  }
+
+  public static final class Policy.RoamingPartner implements android.os.Parcelable {
+    ctor public Policy.RoamingPartner();
+    ctor public Policy.RoamingPartner(android.net.wifi.hotspot2.pps.Policy.RoamingPartner);
+    method public int describeContents();
+    method public java.lang.String getCountries();
+    method public java.lang.String getFqdn();
+    method public boolean getFqdnExactMatch();
+    method public int getPriority();
+    method public void setCountries(java.lang.String);
+    method public void setFqdn(java.lang.String);
+    method public void setFqdnExactMatch(boolean);
+    method public void setPriority(int);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Policy.RoamingPartner> CREATOR;
+  }
+
+  public final class UpdateParameter implements android.os.Parcelable {
+    ctor public UpdateParameter();
+    ctor public UpdateParameter(android.net.wifi.hotspot2.pps.UpdateParameter);
+    method public int describeContents();
+    method public java.lang.String getBase64EncodedPassword();
+    method public java.lang.String getRestriction();
+    method public java.lang.String getServerUri();
+    method public byte[] getTrustRootCertSha256Fingerprint();
+    method public java.lang.String getTrustRootCertUrl();
+    method public long getUpdateIntervalInMinutes();
+    method public java.lang.String getUpdateMethod();
+    method public java.lang.String getUsername();
+    method public void setBase64EncodedPassword(java.lang.String);
+    method public void setRestriction(java.lang.String);
+    method public void setServerUri(java.lang.String);
+    method public void setTrustRootCertSha256Fingerprint(byte[]);
+    method public void setTrustRootCertUrl(java.lang.String);
+    method public void setUpdateIntervalInMinutes(long);
+    method public void setUpdateMethod(java.lang.String);
+    method public void setUsername(java.lang.String);
+    method public boolean validate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.UpdateParameter> CREATOR;
+    field public static final long UPDATE_CHECK_INTERVAL_NEVER = 4294967295L; // 0xffffffffL
+    field public static final java.lang.String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
+    field public static final java.lang.String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
+    field public static final java.lang.String UPDATE_RESTRICTION_HOMESP = "HomeSP";
+    field public static final java.lang.String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
+    field public static final java.lang.String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
+  }
+
+}
+
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -36421,9 +36662,11 @@
     method public android.telecom.Call.Details getDetails();
     method public android.telecom.Call getParent();
     method public java.lang.String getRemainingPostDialSequence();
+    method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
     method public void hold();
+    method public boolean isRttActive();
     method public void mergeConference();
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
@@ -36435,9 +36678,12 @@
     method public void reject(boolean, java.lang.String);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
+    method public void respondToRttRequest(int, boolean);
     method public void sendCallEvent(java.lang.String, android.os.Bundle);
+    method public void sendRttRequest();
     method public void splitFromConference();
     method public void stopDtmfTone();
+    method public void stopRtt();
     method public void swapConference();
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36464,6 +36710,9 @@
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
+    method public void onRttModeChanged(android.telecom.Call, int);
+    method public void onRttRequest(android.telecom.Call, int);
+    method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
   }
@@ -36517,6 +36766,16 @@
     field public static final int PROPERTY_WIFI = 8; // 0x8
   }
 
+  public static final class Call.RttCall {
+    method public int getRttAudioMode();
+    method public java.lang.String read();
+    method public void setRttMode(int);
+    method public void write(java.lang.String) throws java.io.IOException;
+    field public static final int RTT_MODE_FULL = 1; // 0x1
+    field public static final int RTT_MODE_HCO = 2; // 0x2
+    field public static final int RTT_MODE_VCO = 3; // 0x3
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
@@ -36736,6 +36995,7 @@
     method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void setCallDataUsage(long);
     field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; // 0x7
     field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
     field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
     field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
@@ -36887,6 +37147,7 @@
     field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_RTT = 4096; // 0x1000
     field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37099,6 +37360,7 @@
     field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -37252,6 +37514,7 @@
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
     field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
     field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
     field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -38578,7 +38841,7 @@
 
 package android.test.suitebuilder {
 
-  public class TestMethod {
+  public deprecated class TestMethod {
     ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
     ctor public TestMethod(junit.framework.TestCase);
@@ -38589,7 +38852,7 @@
     method public java.lang.String getName();
   }
 
-  public class TestSuiteBuilder {
+  public deprecated class TestSuiteBuilder {
     ctor public TestSuiteBuilder(java.lang.Class);
     ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
     method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -38602,7 +38865,7 @@
     method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
   }
 
-  public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+  public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
     ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
     method public void testSuiteConstructionFailed();
   }
@@ -48979,7 +49242,7 @@
 
 package com.android.internal.util {
 
-  public abstract interface Predicate<T> {
+  public abstract deprecated interface Predicate<T> {
     method public abstract boolean apply(T);
   }
 
@@ -49117,6 +49380,8 @@
     field public static final int OP_INT_TO_FLOAT = 130; // 0x82
     field public static final int OP_INT_TO_LONG = 129; // 0x81
     field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+    field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+    field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
     field public static final int OP_INVOKE_DIRECT = 112; // 0x70
     field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
     field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -49124,6 +49389,8 @@
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
     field public static final int OP_INVOKE_INTERFACE_JUMBO = 9983; // 0x26ff
     field public static final int OP_INVOKE_INTERFACE_RANGE = 120; // 0x78
+    field public static final int OP_INVOKE_POLYMORPHIC = 250; // 0xfa
+    field public static final int OP_INVOKE_POLYMORPHIC_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_STATIC = 113; // 0x71
     field public static final int OP_INVOKE_STATIC_JUMBO = 9727; // 0x25ff
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
@@ -49305,7 +49572,7 @@
     method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
-  public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+  public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
   }
 
@@ -50523,6 +50790,13 @@
     field public static final java.lang.Class<java.lang.Boolean> TYPE;
   }
 
+  public class BootstrapMethodError extends java.lang.LinkageError {
+    ctor public BootstrapMethodError();
+    ctor public BootstrapMethodError(java.lang.String);
+    ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+    ctor public BootstrapMethodError(java.lang.Throwable);
+  }
+
   public final class Byte extends java.lang.Number implements java.lang.Comparable {
     ctor public Byte(byte);
     ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -52409,6 +52683,21 @@
 
 package java.lang.invoke {
 
+  public abstract class CallSite {
+    method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+    method public abstract java.lang.invoke.MethodHandle getTarget();
+    method public abstract void setTarget(java.lang.invoke.MethodHandle);
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public class ConstantCallSite extends java.lang.invoke.CallSite {
+    ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+    ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public final void setTarget(java.lang.invoke.MethodHandle);
+  }
+
   public class LambdaConversionException extends java.lang.Exception {
     ctor public LambdaConversionException();
     ctor public LambdaConversionException(java.lang.String);
@@ -52418,12 +52707,15 @@
   }
 
   public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
     method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
     method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
     method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
     method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
     method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
@@ -52457,17 +52749,23 @@
     method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
     method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
     method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
   }
 
@@ -52484,7 +52782,7 @@
     method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
-    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -52527,6 +52825,22 @@
     method public java.lang.invoke.MethodType wrap();
   }
 
+  public class MutableCallSite extends java.lang.invoke.CallSite {
+    ctor public MutableCallSite(java.lang.invoke.MethodType);
+    ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public void setTarget(java.lang.invoke.MethodHandle);
+  }
+
+  public class VolatileCallSite extends java.lang.invoke.CallSite {
+    ctor public VolatileCallSite(java.lang.invoke.MethodType);
+    ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+    method public final java.lang.invoke.MethodHandle dynamicInvoker();
+    method public final java.lang.invoke.MethodHandle getTarget();
+    method public void setTarget(java.lang.invoke.MethodHandle);
+  }
+
   public class WrongMethodTypeException extends java.lang.RuntimeException {
     ctor public WrongMethodTypeException();
     ctor public WrongMethodTypeException(java.lang.String);
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 4dcb05e..adbe9d0 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -36,8 +36,8 @@
     public String longHelp() {
         return shortHelp() + "\n"
                 + "\n"
-                + "usage: svc usb setFunction [function]\n"
-                + "         Set the current usb function.\n\n"
+                + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n"
+                + "         Set the current usb function and optionally the data lock state.\n\n"
                 + "       svc usb getFunction\n"
                 + "          Gets the list of currently enabled functions\n";
     }
@@ -49,8 +49,12 @@
             if ("setFunction".equals(args[1])) {
                 IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
                         Context.USB_SERVICE));
+                boolean unlockData = false;
+                if (args.length >= 4) {
+                    unlockData = Boolean.valueOf(args[3]);
+                }
                 try {
-                    usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), false);
+                    usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), unlockData);
                 } catch (RemoteException e) {
                     System.err.println("Error communicating with UsbManager: " + e);
                 }
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 63f6c92..8e9b91d 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.IUserManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -51,6 +50,7 @@
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
     private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
+    private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
 
     private ComponentName mComponent;
     private String mAccountId;
@@ -69,6 +69,7 @@
                 "usage: telecom set-default-dialer <PACKAGE>\n" +
                 "usage: telecom get-default-dialer\n" +
                 "usage: telecom get-system-dialer\n" +
+                "usage: telecom wait-on-handlers\n" +
                 "\n" +
                 "telecom set-phone-account-enabled: Enables the given phone account, if it has \n" +
                 " already been registered with Telecom.\n" +
@@ -80,7 +81,9 @@
                 "\n" +
                 "telecom get-default-dialer: Displays the current default dialer. \n" +
                 "\n" +
-                "telecom get-system-dialer: Displays the current system dialer. \n"
+                "telecom get-system-dialer: Displays the current system dialer. \n" +
+                "\n" +
+                "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
                 );
     }
 
@@ -125,6 +128,9 @@
             case COMMAND_GET_SYSTEM_DIALER:
                 runGetSystemDialer();
                 break;
+            case COMMAND_WAIT_ON_HANDLERS:
+                runWaitOnHandler();
+                break;
             default:
                 throw new IllegalArgumentException ("unknown command '" + command + "'");
         }
@@ -192,6 +198,10 @@
         System.out.println(mTelecomService.getSystemDialerPackage());
     }
 
+    private void runWaitOnHandler() throws RemoteException {
+
+    }
+
     private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException{
         final ComponentName component = parseComponentName(nextArgRequired());
         final String accountId = nextArgRequired();
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
index 73e46f1..28a5646 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/InteractionController.java
@@ -32,8 +32,6 @@
 import android.view.MotionEvent.PointerProperties;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.internal.util.Predicate;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -261,7 +259,7 @@
     }
 
     /**
-     * Returns a Runnable for use in {@link #runAndWaitForEvents(Runnable, Predicate, long) to
+     * Returns a Runnable for use in {@link #runAndWaitForEvents(Runnable, AccessibilityEventFilter, long) to
      * perform a click.
      *
      * @param x coordinate
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cae4be6..c7fc860 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -974,6 +974,10 @@
             sendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0, 0, true /*async*/);
         }
 
+        public void attachAgent(String agent) {
+            sendMessage(H.ATTACH_AGENT, agent);
+        }
+
         public void setSchedulingGroup(int group) {
             // Note: do this immediately, since going into the foreground
             // should happen regardless of what pending work we have to do
@@ -1408,6 +1412,7 @@
         public static final int MULTI_WINDOW_MODE_CHANGED = 152;
         public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
         public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
+        public static final int ATTACH_AGENT = 155;
 
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
@@ -1464,6 +1469,7 @@
                     case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
                     case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
                     case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
+                    case ATTACH_AGENT: return "ATTACH_AGENT";
                 }
             }
             return Integer.toString(code);
@@ -1719,6 +1725,9 @@
                     handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
                             (IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
                     break;
+                case ATTACH_AGENT:
+                    handleAttachAgent((String) msg.obj);
+                    break;
             }
             Object obj = msg.obj;
             if (obj instanceof SomeArgs) {
@@ -2987,6 +2996,14 @@
         }
     }
 
+    static final void handleAttachAgent(String agent) {
+        try {
+            VMDebug.attachAgent(agent);
+        } catch (IOException e) {
+            Slog.e(TAG, "Attaching agent failed: " + agent);
+        }
+    }
+
     private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
 
     /**
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 05d9d7e..ad7f577 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -502,6 +502,14 @@
             return true;
         }
 
+        case ATTACH_AGENT_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            String agent = data.readString();
+            attachAgent(agent);
+            return true;
+        }
+
         case DUMP_ACTIVITY_TRANSACTION: {
             data.enforceInterface(IApplicationThread.descriptor);
             ParcelFileDescriptor fd = data.readFileDescriptor();
@@ -1305,6 +1313,14 @@
         data.recycle();
     }
 
+    public void attachAgent(String agent) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeString(agent);
+        mRemote.transact(ATTACH_AGENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
+
     public void setCoreSettings(Bundle coreSettings) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 3fa88ae..bfd97f8 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -123,6 +123,7 @@
             throws RemoteException;
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
             throws RemoteException;
+    void attachAgent(String path) throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
     // the package has been removed, clean up internal references
     static final int PACKAGE_REMOVED = 0;
@@ -225,4 +226,5 @@
     int SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
     int SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
     int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60;
+    int ATTACH_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61;
 }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index afe9651..e00a7f0 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -266,7 +266,7 @@
         setApplicationInfo(aInfo);
 
         final List<String> newPaths = new ArrayList<>();
-        makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+        makePaths(mActivityThread, aInfo, newPaths);
         final List<String> addedPaths = new ArrayList<>(newPaths.size());
 
         if (oldPaths != null) {
@@ -314,8 +314,17 @@
         mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
     }
 
-    public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
-            List<String> outZipPaths, List<String> outLibPaths) {
+    public static void makePaths(ActivityThread activityThread,
+                                 ApplicationInfo aInfo,
+                                 List<String> outZipPaths) {
+        makePaths(activityThread, false, aInfo, outZipPaths, null);
+    }
+
+    public static void makePaths(ActivityThread activityThread,
+                                 boolean isBundledApp,
+                                 ApplicationInfo aInfo,
+                                 List<String> outZipPaths,
+                                 List<String> outLibPaths) {
         final String appDir = aInfo.sourceDir;
         final String[] splitAppDirs = aInfo.splitSourceDirs;
         final String libDir = aInfo.nativeLibraryDir;
@@ -398,7 +407,7 @@
                 }
             }
 
-            if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+            if (isBundledApp) {
                 // Add path to system libraries to libPaths;
                 // Access to system libs should be limited
                 // to bundled applications; this is why updated
@@ -471,11 +480,12 @@
         // space and initialize to a small value (instead of incurring growth code).
         final List<String> zipPaths = new ArrayList<>(10);
         final List<String> libPaths = new ArrayList<>(10);
-        makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
 
         final boolean isBundledApp = mApplicationInfo.isSystemApp()
                 && !mApplicationInfo.isUpdatedSystemApp();
 
+        makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
+
         String libraryPermittedPath = mDataDir;
         if (isBundledApp) {
             // This is necessary to grant bundled apps access to
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index a482103..176e48f 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -37,9 +37,11 @@
     public static final int SOURCE_CODEC_TYPE_APTX    = 2;
     public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
     public static final int SOURCE_CODEC_TYPE_LDAC    = 4;
+    public static final int SOURCE_CODEC_TYPE_MAX     = 5;
 
     public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
 
+    public static final int CODEC_PRIORITY_DISABLED = -1;
     public static final int CODEC_PRIORITY_DEFAULT = 0;
     public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
 
@@ -72,7 +74,7 @@
 
     public BluetoothCodecConfig(int codecType, int codecPriority,
                                 int sampleRate, int bitsPerSample,
-                                int channelMode,long codecSpecific1,
+                                int channelMode, long codecSpecific1,
                                 long codecSpecific2, long codecSpecific3,
                                 long codecSpecific4) {
         mCodecType = codecType;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6aaa48..b7876d9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1096,6 +1096,15 @@
     public static final String ACTION_SIM_ACTIVATION_REQUEST =
             "android.intent.action.SIM_ACTIVATION_REQUEST";
     /**
+     * Activity Action: Main entry point for carrier setup apps.
+     * <p>Carrier apps that provide an implementation for this action may be invoked to configure
+     * carrier service and typically require
+     * {@link android.telephony.TelephonyManager#hasCarrierPrivileges() carrier privileges} to
+     * fulfill their duties.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+    /**
      * Activity Action: Send a message to someone specified by the data.
      * <p>Input: {@link #getData} is URI describing the target.
      * <p>Output: nothing.
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index bb0a042..5423ca9 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -646,7 +646,7 @@
 
         // Special case where the only scene mode listed is AUTO => no scene mode
         if (sceneModes != null && sceneModes.size() == 1 &&
-                sceneModes.get(0) == Parameters.SCENE_MODE_AUTO) {
+                sceneModes.get(0).equals(Parameters.SCENE_MODE_AUTO)) {
             supportedSceneModes = null;
         }
 
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 042481f..30afdc2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -46,6 +46,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.PhoneConstants;
@@ -1219,36 +1220,27 @@
 
     private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
         if (networkType == TYPE_MOBILE) {
-            int cap = -1;
-            if ("enableMMS".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_MMS;
-            } else if ("enableSUPL".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_SUPL;
-            } else if ("enableDUN".equals(feature) || "enableDUNAlways".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_DUN;
-            } else if ("enableHIPRI".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_INTERNET;
-            } else if ("enableFOTA".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_FOTA;
-            } else if ("enableIMS".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_IMS;
-            } else if ("enableCBS".equals(feature)) {
-                cap = NetworkCapabilities.NET_CAPABILITY_CBS;
-            } else {
-                return null;
+            switch (feature) {
+                case "enableCBS":
+                    return networkCapabilitiesForType(TYPE_MOBILE_CBS);
+                case "enableDUN":
+                case "enableDUNAlways":
+                    return networkCapabilitiesForType(TYPE_MOBILE_DUN);
+                case "enableFOTA":
+                    return networkCapabilitiesForType(TYPE_MOBILE_FOTA);
+                case "enableHIPRI":
+                    return networkCapabilitiesForType(TYPE_MOBILE_HIPRI);
+                case "enableIMS":
+                    return networkCapabilitiesForType(TYPE_MOBILE_IMS);
+                case "enableMMS":
+                    return networkCapabilitiesForType(TYPE_MOBILE_MMS);
+                case "enableSUPL":
+                    return networkCapabilitiesForType(TYPE_MOBILE_SUPL);
+                default:
+                    return null;
             }
-            NetworkCapabilities netCap = new NetworkCapabilities();
-            netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
-            netCap.maybeMarkCapabilitiesRestricted();
-            return netCap;
-        } else if (networkType == TYPE_WIFI) {
-            if ("p2p".equals(feature)) {
-                NetworkCapabilities netCap = new NetworkCapabilities();
-                netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-                netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
-                netCap.maybeMarkCapabilitiesRestricted();
-                return netCap;
-            }
+        } else if (networkType == TYPE_WIFI && "p2p".equals(feature)) {
+            return networkCapabilitiesForType(TYPE_WIFI_P2P);
         }
         return null;
     }
@@ -1429,8 +1421,8 @@
         l.networkCapabilities = netCap;
         l.delay = delay;
         l.expireSequenceNumber = 0;
-        l.networkRequest = sendRequestForNetwork(netCap, l.networkCallback, 0,
-                REQUEST, type);
+        l.networkRequest = sendRequestForNetwork(
+                netCap, l.networkCallback, 0, REQUEST, type, getDefaultHandler());
         if (l.networkRequest == null) return null;
         sLegacyRequests.put(netCap, l);
         sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay);
@@ -1440,8 +1432,9 @@
     private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) {
         if (delay >= 0) {
             Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay);
-            Message msg = sCallbackHandler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
-            sCallbackHandler.sendMessageDelayed(msg, delay);
+            CallbackHandler handler = getDefaultHandler();
+            Message msg = handler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
+            handler.sendMessageDelayed(msg, delay);
         }
     }
 
@@ -1456,6 +1449,59 @@
         return true;
     }
 
+    private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray();
+    static {
+        sLegacyTypeToTransport.put(TYPE_MOBILE,       NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_CBS,   NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_DUN,   NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_FOTA,  NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_IMS,   NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_MMS,   NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_MOBILE_SUPL,  NetworkCapabilities.TRANSPORT_CELLULAR);
+        sLegacyTypeToTransport.put(TYPE_WIFI,         NetworkCapabilities.TRANSPORT_WIFI);
+        sLegacyTypeToTransport.put(TYPE_WIFI_P2P,     NetworkCapabilities.TRANSPORT_WIFI);
+        sLegacyTypeToTransport.put(TYPE_BLUETOOTH,    NetworkCapabilities.TRANSPORT_BLUETOOTH);
+        sLegacyTypeToTransport.put(TYPE_ETHERNET,     NetworkCapabilities.TRANSPORT_ETHERNET);
+    }
+
+    private static final SparseIntArray sLegacyTypeToCapability = new SparseIntArray();
+    static {
+        sLegacyTypeToCapability.put(TYPE_MOBILE_CBS,  NetworkCapabilities.NET_CAPABILITY_CBS);
+        sLegacyTypeToCapability.put(TYPE_MOBILE_DUN,  NetworkCapabilities.NET_CAPABILITY_DUN);
+        sLegacyTypeToCapability.put(TYPE_MOBILE_FOTA, NetworkCapabilities.NET_CAPABILITY_FOTA);
+        sLegacyTypeToCapability.put(TYPE_MOBILE_IMS,  NetworkCapabilities.NET_CAPABILITY_IMS);
+        sLegacyTypeToCapability.put(TYPE_MOBILE_MMS,  NetworkCapabilities.NET_CAPABILITY_MMS);
+        sLegacyTypeToCapability.put(TYPE_MOBILE_SUPL, NetworkCapabilities.NET_CAPABILITY_SUPL);
+        sLegacyTypeToCapability.put(TYPE_WIFI_P2P,    NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+    }
+
+    /**
+     * Given a legacy type (TYPE_WIFI, ...) returns a NetworkCapabilities
+     * instance suitable for registering a request or callback.  Throws an
+     * IllegalArgumentException if no mapping from the legacy type to
+     * NetworkCapabilities is known.
+     *
+     * @hide
+     */
+    public static NetworkCapabilities networkCapabilitiesForType(int type) {
+        final NetworkCapabilities nc = new NetworkCapabilities();
+
+        // Map from type to transports.
+        final int NOT_FOUND = -1;
+        final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
+        if (transport == NOT_FOUND) {
+            throw new IllegalArgumentException("unknown legacy type: " + type);
+        }
+        nc.addTransportType(transport);
+
+        // Map from type to capabilities.
+        nc.addCapability(sLegacyTypeToCapability.get(
+                type, NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        nc.maybeMarkCapabilitiesRestricted();
+        return nc;
+    }
+
     /** @hide */
     public static class PacketKeepaliveCallback {
         /** The requested keepalive was successfully started. */
@@ -2705,6 +2751,10 @@
             super(looper);
         }
 
+        CallbackHandler(Handler handler) {
+            this(handler.getLooper());
+        }
+
         @Override
         public void handleMessage(Message message) {
             NetworkRequest request = getObject(message, NetworkRequest.class);
@@ -2814,7 +2864,7 @@
         }
     }
 
-    private CallbackHandler getHandler() {
+    private CallbackHandler getDefaultHandler() {
         synchronized (sCallbacks) {
             if (sCallbackHandler == null) {
                 sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper());
@@ -2823,19 +2873,14 @@
         }
     }
 
-    static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
-    static CallbackHandler sCallbackHandler;
+    private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
+    private static CallbackHandler sCallbackHandler;
 
-    private final static int LISTEN  = 1;
-    private final static int REQUEST = 2;
+    private static final int LISTEN  = 1;
+    private static final int REQUEST = 2;
 
-    private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
-            NetworkCallback callback, int timeoutMs, int action, int legacyType) {
-        return sendRequestForNetwork(need, callback, getHandler(), timeoutMs, action, legacyType);
-    }
-
-    private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
-            NetworkCallback callback, Handler handler, int timeoutMs, int action, int legacyType) {
+    private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
+            int timeoutMs, int action, int legacyType, CallbackHandler handler) {
         if (callback == null) {
             throw new IllegalArgumentException("null NetworkCallback");
         }
@@ -2878,9 +2923,10 @@
      * @hide
      */
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            int timeoutMs, int legacyType) {
-        sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs, REQUEST,
-                legacyType);
+            int timeoutMs, int legacyType, Handler handler) {
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        NetworkCapabilities nc = request.networkCapabilities;
+        sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
     }
 
     /**
@@ -2906,15 +2952,51 @@
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
      * @param request {@link NetworkRequest} describing this request.
-     * @param networkCallback The {@link NetworkCallback} to be utilized for this
-     *                        request.  Note the callback must not be shared - they
-     *                        uniquely specify this request.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
+     *                        The callback is invoked on the default internal Handler.
      * @throws IllegalArgumentException if {@code request} specifies any mutable
      *         {@code NetworkCapabilities}.
      */
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
-        requestNetwork(request, networkCallback, 0,
-                inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
+        requestNetwork(request, networkCallback, getDefaultHandler());
+    }
+
+    /**
+     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+     *
+     * This {@link NetworkRequest} will live until released via
+     * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits.
+     * Status of the request can be followed by listening to the various
+     * callbacks described in {@link NetworkCallback}.  The {@link Network}
+     * can be used to direct traffic to the network.
+     * <p>It is presently unsupported to request a network with mutable
+     * {@link NetworkCapabilities} such as
+     * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+     * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+     * as these {@code NetworkCapabilities} represent states that a particular
+     * network may never attain, and whether a network will attain these states
+     * is unknown prior to bringing up the network so the framework does not
+     * know how to go about satisfing a request with these capabilities.
+     *
+     * <p>This method requires the caller to hold either the
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+     * or the ability to modify system settings as determined by
+     * {@link android.provider.Settings.System#canWrite}.</p>
+     *
+     * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @throws IllegalArgumentException if {@code request} specifies any mutable
+     *         {@code NetworkCapabilities}.
+     * @hide
+     */
+    public void requestNetwork(
+            NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
     }
 
     /**
@@ -2923,7 +3005,36 @@
      *
      * This function behaves identically to the non-timedout version, but if a suitable
      * network is not found within the given time (in milliseconds) the
-     * {@link NetworkCallback#unavailable} callback is called.  The request must
+     * {@link NetworkCallback#onUnavailable()} callback is called.  The request must
+     * still be released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
+     * <p>This method requires the caller to hold either the
+     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+     * or the ability to modify system settings as determined by
+     * {@link android.provider.Settings.System#canWrite}.</p>
+     *
+     * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
+     *                        The callback is invoked on the default internal Handler.
+     * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+     *                  before {@link NetworkCallback#onUnavailable()} is called.
+     * @hide
+     */
+    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+            int timeoutMs) {
+        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
+    }
+
+
+    /**
+     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+     * by a timeout.
+     *
+     * This function behaves identically to the non-timedout version, but if a suitable
+     * network is not found within the given time (in milliseconds) the
+     * {@link NetworkCallback#onUnavailable} callback is called.  The request must
      * still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}.
      *
      * <p>This method requires the caller to hold either the
@@ -2932,30 +3043,22 @@
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
      * @param request {@link NetworkRequest} describing this request.
-     * @param networkCallback The callbacks to be utilized for this request.  Note
-     *                        the callbacks must not be shared - they uniquely specify
-     *                        this request.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
-     *                  before {@link NetworkCallback#unavailable} is called.
-     *
-     * TODO: Make timeouts work and then unhide this method.
+     *                  before {@link NetworkCallback#onUnavailable} is called.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
      *
      * @hide
      */
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            int timeoutMs) {
-        requestNetwork(request, networkCallback, timeoutMs,
-                inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
+            int timeoutMs, Handler handler) {
+        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
     }
 
     /**
-     * The maximum number of milliseconds the framework will look for a suitable network
-     * during a timeout-equiped call to {@link requestNetwork}.
-     * {@hide}
-     */
-    public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000;
-
-    /**
      * The lookup key for a {@link Network} object included with the intent after
      * successfully finding a network for the applications request.  Retrieve it with
      * {@link android.content.Intent#getParcelableExtra(String)}.
@@ -3066,9 +3169,30 @@
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
      *                        networks change state.
+     *                        The callback is invoked on the default internal Handler.
      */
     public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
-        sendRequestForNetwork(request.networkCapabilities, networkCallback, 0, LISTEN, TYPE_NONE);
+        registerNetworkCallback(request, networkCallback, getDefaultHandler());
+    }
+
+    /**
+     * Registers to receive notifications about all networks which satisfy the given
+     * {@link NetworkRequest}.  The callbacks will continue to be called until
+     * either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+     *                        networks change state.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @hide
+     */
+    public void registerNetworkCallback(
+            NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        NetworkCapabilities nc = request.networkCapabilities;
+        sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
     }
 
     /**
@@ -3120,8 +3244,25 @@
      *
      * @param networkCallback The {@link NetworkCallback} that the system will call as the
      *                        system default network changes.
+     *                        The callback is invoked on the default internal Handler.
      */
     public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+        registerDefaultNetworkCallback(networkCallback, getDefaultHandler());
+    }
+
+    /**
+     * Registers to receive notifications about changes in the system default network. The callbacks
+     * will continue to be called until either the application exits or
+     * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @param networkCallback The {@link NetworkCallback} that the system will call as the
+     *                        system default network changes.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @hide
+     */
+    public void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) {
         // This works because if the NetworkCapabilities are null,
         // ConnectivityService takes them from the default request.
         //
@@ -3129,7 +3270,8 @@
         // capabilities, this request is guaranteed, at all times, to be
         // satisfied by the same network, if any, that satisfies the default
         // request, i.e., the system default network.
-        sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE);
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
     }
 
     /**
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 9a2d4e0..67b6908 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -46,32 +46,7 @@
 
     public static final String DATA_KEY_EVENTS_COUNT = "count";
 
-    /** {@hide} */ protected IConnectivityMetricsLogger mService;
-    /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis;
-    private int mNumSkippedEvents;
-
     public ConnectivityMetricsLogger() {
-        // TODO: consider not initializing mService in constructor
-        this(IConnectivityMetricsLogger.Stub.asInterface(
-                ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE)));
-    }
-
-    /** {@hide} */
-    @VisibleForTesting
-    public ConnectivityMetricsLogger(IConnectivityMetricsLogger service) {
-        mService = service;
-    }
-
-    /** {@hide} */
-    protected boolean checkLoggerService() {
-        if (mService != null) {
-            return true;
-        }
-        // Two threads racing here will write the same pointer because getService
-        // is idempotent once MetricsLoggerService is initialized.
-        mService = IConnectivityMetricsLogger.Stub.asInterface(
-                ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE));
-        return mService != null;
     }
 
     /**
@@ -88,62 +63,6 @@
      * @param data is a Parcelable instance representing the event.
      */
     public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
-        if (mService == null) {
-            if (DBG) {
-                Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
-            }
-            return;
-        }
-
-        if (mServiceUnblockedTimestampMillis > 0) {
-            if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
-                // Service is throttling events.
-                // Don't send new events because they will be dropped.
-                mNumSkippedEvents++;
-                return;
-            }
-        }
-
-        ConnectivityMetricsEvent skippedEventsEvent = null;
-        if (mNumSkippedEvents > 0) {
-            // Log number of skipped events
-            Bundle b = new Bundle();
-            b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
-
-            // Log the skipped event.
-            // TODO: Note that some of the clients push all states events into the server,
-            // If we lose some states logged here, we might mess up the statistics happened at the
-            // backend. One of the options is to introduce a non-skippable flag for important events
-            // that are logged.
-            skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
-                    componentTag, TAG_SKIPPED_EVENTS, b);
-
-            mServiceUnblockedTimestampMillis = 0;
-        }
-
-        ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
-                eventTag, data);
-
-        try {
-            long result;
-            if (skippedEventsEvent == null) {
-                result = mService.logEvent(event);
-            } else {
-                result = mService.logEvents(new ConnectivityMetricsEvent[]
-                        {skippedEventsEvent, event});
-            }
-
-            if (result == 0) {
-                mNumSkippedEvents = 0;
-            } else {
-                mNumSkippedEvents++;
-                if (result > 0) { // events are throttled
-                    mServiceUnblockedTimestampMillis = result;
-                }
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error logging event", e);
-        }
     }
 
     /**
@@ -157,33 +76,17 @@
      * @return events
      */
     public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
-        try {
-            return mService.getEvents(reference);
-        } catch (RemoteException e) {
-            Log.e(TAG, "IConnectivityMetricsLogger.getEvents", e);
-            return null;
-        }
+        return new ConnectivityMetricsEvent[0];
     }
 
     /**
      * Register PendingIntent which will be sent when new events are ready to be retrieved.
      */
     public boolean register(PendingIntent newEventsIntent) {
-        try {
-            return mService.register(newEventsIntent);
-        } catch (RemoteException e) {
-            Log.e(TAG, "IConnectivityMetricsLogger.register", e);
-            return false;
-        }
+        return false;
     }
 
     public boolean unregister(PendingIntent newEventsIntent) {
-        try {
-            mService.unregister(newEventsIntent);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG, "IConnectivityMetricsLogger.unregister", e);
-            return false;
-        }
+        return false;
     }
 }
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index ae72470..cb78009 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -178,6 +178,20 @@
         }
 
         /**
+         * Set the {@code NetworkCapabilities} for this builder instance,
+         * overriding any capabilities that had been previously set.
+         *
+         * @param nc The superseding {@code NetworkCapabilities} instance.
+         * @return The builder to facilitate chaining.
+         * @hide
+         */
+        public Builder setCapabilities(NetworkCapabilities nc) {
+            mNetworkCapabilities.clearAll();
+            mNetworkCapabilities.combineCapabilities(nc);
+            return this;
+        }
+
+        /**
          * Completely clears all the {@code NetworkCapabilities} from this builder instance,
          * removing even the capabilities that are set by default when the object is constructed.
          *
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 210ddb6..e05bd89 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2219,11 +2219,13 @@
     }
 
     /**
-     * Have the stack traces of the given native process dumped to the
-     * specified file.  Will be appended to the file.
+     * Append the stack traces of a given native process to a specified file.
+     * @param pid pid to dump.
+     * @param file path of file to append dump to.
+     * @param timeoutSecs time to wait in seconds, or 0 to wait forever.
      * @hide
      */
-    public static native void dumpNativeBacktraceToFile(int pid, String file);
+    public static native void dumpNativeBacktraceToFileTimeout(int pid, String file, int timeoutSecs);
 
     /**
      * Get description of unreachable native memory.
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl b/core/java/android/os/Seccomp.java
similarity index 69%
copy from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
copy to core/java/android/os/Seccomp.java
index 62d5603..f14e93f 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
+++ b/core/java/android/os/Seccomp.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot2.pps;
+package android.os;
 
-parcelable HomeSP;
+/**
+ * @hide
+ */
+public final class Seccomp {
+    public static final native void setPolicy();
+}
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index fc804e5..0b4c4c1 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -274,7 +274,7 @@
     /**
      * Implement parsing and execution of a command.  If it isn't a command you understand,
      * call {@link #handleDefaultCommands(String)} and return its result as a last resort.
-     * User {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
+     * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
      * to process additional command line arguments.  Command output can be written to
      * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
      *
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 1ec00db..f1d59e2 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -348,8 +348,8 @@
             if (msg.what == UPDATE_SLIDER) {
                 if (mSeekBar != null) {
                     mLastProgress = msg.arg1;
-                    mLastAudibleStreamVolume = Math.abs(msg.arg2);
-                    final boolean muted = msg.arg2 < 0;
+                    mLastAudibleStreamVolume = msg.arg2;
+                    final boolean muted = ((Boolean)msg.obj).booleanValue();
                     if (muted != mMuted) {
                         mMuted = muted;
                         if (mCallback != null) {
@@ -362,8 +362,7 @@
         }
 
         public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
-            final int arg2 = lastAudibleVolume * (mute ? -1 : 1);
-            obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget();
+            obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
         }
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b1dcb81..38ad68d 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6416,6 +6416,12 @@
         public static final String DEVICE_PAIRED = "device_paired";
 
         /**
+         * Specifies additional package name for broadcasting the CMAS messages.
+         * @hide
+         */
+        public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -7692,6 +7698,16 @@
         public static final String NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS =
                 "network_recommendation_request_timeout_ms";
 
+        /**
+         * The expiration time in milliseconds for the {@link android.net.WifiKey} request cache in
+         * {@link com.android.server.wifi.RecommendedNetworkEvaluator}.
+         *
+         * Type: long
+         * @hide
+         */
+        public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
+                "recommended_network_evaluator_cache_expiry_ms";
+
        /**
         * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
         * connectivity.
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 887f4b6..1781c2a 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -130,6 +130,11 @@
      */
     public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
 
+    /**
+     * @hide
+     */
+    public static final String EXTRA_STATE = "state";
+
     private final H mHandler = new H(Looper.getMainLooper());
 
     private boolean mListening = false;
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 356804e..80ec03e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -189,7 +189,9 @@
         // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
         String[] availableLanguages = {
             "as",
+            "bg",
             "bn",
+            "cu",
             "cy",
             "da",
             "de-1901", "de-1996", "de-CH-1901",
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index c7b1d03..1c458ab 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -34,7 +34,6 @@
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 
 import com.android.internal.os.SomeArgs;
-import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -43,6 +42,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
+import java.util.function.Predicate;
 
 /**
  * Class for managing accessibility interactions initiated from the system
@@ -1233,7 +1233,7 @@
         }
 
         @Override
-        public boolean apply(View view) {
+        public boolean test(View view) {
             if (view.getId() == mViewId && isShown(view)) {
                 mInfos.add(view.createAccessibilityNodeInfo());
             }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d13f6d6..f65ec94 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -103,7 +103,6 @@
 import static java.lang.Math.max;
 
 import com.android.internal.R;
-import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.widget.ScrollBarUtils;
 import com.google.android.collect.Lists;
@@ -126,6 +125,7 @@
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 
 /**
  * <p>
@@ -8778,7 +8778,7 @@
                 final int id = mID;
                 return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
                     @Override
-                    public boolean apply(View t) {
+                    public boolean test(View t) {
                         return t.mNextFocusForwardId == id;
                     }
                 });
@@ -19349,7 +19349,7 @@
      * @return The first view that matches the predicate or null.
      */
     protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
-        if (predicate.apply(this)) {
+        if (predicate.test(this)) {
             return this;
         }
         return null;
@@ -23639,20 +23639,20 @@
         }
     }
 
-    private class MatchIdPredicate implements Predicate<View> {
+    private static class MatchIdPredicate implements Predicate<View> {
         public int mId;
 
         @Override
-        public boolean apply(View view) {
+        public boolean test(View view) {
             return (view.mID == mId);
         }
     }
 
-    private class MatchLabelForPredicate implements Predicate<View> {
+    private static class MatchLabelForPredicate implements Predicate<View> {
         private int mLabeledId;
 
         @Override
-        public boolean apply(View view) {
+        public boolean test(View view) {
             return (view.mLabelForId == mLabeledId);
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d4b7d3b..776f119 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -52,13 +52,13 @@
 import android.view.animation.Transformation;
 
 import com.android.internal.R;
-import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 
@@ -3994,7 +3994,7 @@
      */
     @Override
     protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
-        if (predicate.apply(this)) {
+        if (predicate.test(this)) {
             return this;
         }
 
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 2d6f443..f9d7332 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -176,7 +176,7 @@
             // paths and pass them to the zygote as strings.
             final List<String> zipPaths = new ArrayList<>(10);
             final List<String> libPaths = new ArrayList<>(10);
-            LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
+            LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
             final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
             final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
                     TextUtils.join(File.pathSeparator, zipPaths);
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index 5f0ae29..07b3c95 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -25,11 +25,11 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 
-import com.android.internal.util.Predicate;
 import com.android.internal.widget.PagerAdapter;
 import com.android.internal.widget.ViewPager;
 
 import java.util.ArrayList;
+import java.util.function.Predicate;
 
 /**
  * This displays a list of months in a calendar format with selectable days.
@@ -143,7 +143,7 @@
 
     @Override
     protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
-        if (predicate.apply(this)) {
+        if (predicate.test(this)) {
             return this;
         }
 
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b0f19d7..2e7f0fd 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -19,7 +19,6 @@
 import com.google.android.collect.Lists;
 
 import com.android.internal.R;
-import com.android.internal.util.Predicate;
 
 import android.annotation.IdRes;
 import android.annotation.NonNull;
@@ -55,6 +54,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Predicate;
 
 /*
  * Implementation Notes:
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index c851e4e..674fdea 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -43,8 +43,8 @@
  * @hide
  */
 public class RuntimeInit {
-    private final static String TAG = "AndroidRuntime";
-    private final static boolean DEBUG = false;
+    final static String TAG = "AndroidRuntime";
+    final static boolean DEBUG = false;
 
     /** true if commonInit() has been called */
     private static boolean initialized;
@@ -53,7 +53,6 @@
 
     private static volatile boolean mCrashing = false;
 
-    private static final native void nativeZygoteInit();
     private static final native void nativeFinishInit();
     private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
 
@@ -133,7 +132,7 @@
         }
     }
 
-    private static final void commonInit() {
+    protected static final void commonInit() {
         if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
 
         /*
@@ -287,50 +286,7 @@
         if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
     }
 
-    /**
-     * The main function called when started through the zygote process. This
-     * could be unified with main(), if the native code in nativeFinishInit()
-     * were rationalized with Zygote startup.<p>
-     *
-     * Current recognized args:
-     * <ul>
-     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
-     * </ul>
-     *
-     * @param targetSdkVersion target SDK version
-     * @param argv arg strings
-     */
-    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
-            throws Zygote.MethodAndArgsCaller {
-        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
-
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
-        redirectLogStreams();
-
-        commonInit();
-        nativeZygoteInit();
-        applicationInit(targetSdkVersion, argv, classLoader);
-    }
-
-    /**
-     * The main function called when an application is started through a
-     * wrapper process.
-     *
-     * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
-     * which calls {@link WrapperInit#main} which then calls this method.
-     * So we don't need to call commonInit() here.
-     *
-     * @param targetSdkVersion target SDK version
-     * @param argv arg strings
-     */
-    public static void wrapperInit(int targetSdkVersion, String[] argv)
-            throws Zygote.MethodAndArgsCaller {
-        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
-
-        applicationInit(targetSdkVersion, argv, null);
-    }
-
-    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
+    protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
             throws Zygote.MethodAndArgsCaller {
         // If the application calls System.exit(), terminate the process
         // immediately without running any shutdown hooks.  It is not possible to
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 594b6ab..dbbebbe7 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -18,7 +18,7 @@
 
 import android.os.Process;
 import android.util.Slog;
-
+import com.android.internal.os.Zygote.MethodAndArgsCaller;
 import dalvik.system.VMRuntime;
 import java.io.DataOutputStream;
 import java.io.FileDescriptor;
@@ -80,7 +80,7 @@
             // Launch the application.
             String[] runtimeArgs = new String[args.length - 2];
             System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
-            RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
+            WrapperInit.wrapperInit(targetSdkVersion, runtimeArgs);
         } catch (Zygote.MethodAndArgsCaller caller) {
             caller.run();
         }
@@ -121,4 +121,24 @@
         Zygote.appendQuotedShellArgs(command, args);
         Zygote.execShell(command.toString());
     }
+
+    /**
+     * The main function called when an application is started through a
+     * wrapper process.
+     *
+     * When the wrapper starts, the runtime starts {@link RuntimeInit#main}
+     * which calls {@link main} which then calls this method.
+     * So we don't need to call commonInit() here.
+     *
+     * @param targetSdkVersion target SDK version
+     * @param argv arg strings
+     */
+    private static void wrapperInit(int targetSdkVersion, String[] argv)
+            throws Zygote.MethodAndArgsCaller {
+        if (RuntimeInit.DEBUG) {
+            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from wrapper");
+        }
+
+        RuntimeInit.applicationInit(targetSdkVersion, argv, null);
+    }
 }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4a6475f..527582b 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -783,7 +783,7 @@
                     VMRuntime.getCurrentInstructionSet(),
                     pipeFd, parsedArgs.remainingArgs);
         } else {
-            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
+            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                     parsedArgs.remainingArgs, null /* classLoader */);
         }
     }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ef5231c..1e0a998 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -29,6 +29,7 @@
 import android.os.IInstalld;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.Seccomp;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.os.SystemClock;
@@ -43,10 +44,9 @@
 import android.text.Hyphenator;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Slog;
 import android.webkit.WebViewFactory;
 import android.widget.TextView;
-
-
 import dalvik.system.DexFile;
 import dalvik.system.PathClassLoader;
 import dalvik.system.VMRuntime;
@@ -467,7 +467,7 @@
             /*
              * Pass the remaining arguments to SystemServer.
              */
-            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
+            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
         }
 
         /* should never reach here */
@@ -692,6 +692,9 @@
             // Zygote process unmounts root storage spaces.
             Zygote.nativeUnmountStorageOnInit();
 
+            // Set seccomp policy
+            Seccomp.setPolicy();
+
             ZygoteHooks.stopZygoteNoThreadCreation();
 
             if (startSystemServer) {
@@ -747,4 +750,33 @@
      */
     private ZygoteInit() {
     }
+
+    /**
+     * The main function called when started through the zygote process. This
+     * could be unified with main(), if the native code in nativeFinishInit()
+     * were rationalized with Zygote startup.<p>
+     *
+     * Current recognized args:
+     * <ul>
+     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
+     * </ul>
+     *
+     * @param targetSdkVersion target SDK version
+     * @param argv arg strings
+     */
+    public static final void zygoteInit(int targetSdkVersion, String[] argv,
+            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
+        if (RuntimeInit.DEBUG) {
+            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
+        RuntimeInit.redirectLogStreams();
+
+        RuntimeInit.commonInit();
+        ZygoteInit.nativeZygoteInit();
+        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
+    }
+
+    private static final native void nativeZygoteInit();
 }
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
index 184245e..e733c30 100644
--- a/core/java/com/android/internal/util/MessageUtils.java
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -42,10 +42,11 @@
 
     /**
      * Finds the names of integer constants. Searches the specified {@code classes}, looking for
-     * accessible static integer fields whose names begin with one of the specified {@prefixes}.
+     * accessible static integer fields whose names begin with one of the specified
+     * {@code prefixes}.
      *
      * @param classes the classes to examine.
-     * @prefixes only consider fields names starting with one of these prefixes.
+     * @param prefixes only consider fields names starting with one of these prefixes.
      * @return a {@link SparseArray} mapping integer constants to their names.
      */
     public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) {
@@ -122,7 +123,6 @@
      * accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}.
      *
      * @param classNames the classes to examine.
-     * @prefixes only consider fields names starting with one of these prefixes.
      * @return a {@link SparseArray} mapping integer constants to their names.
      */
     public static SparseArray<String> findMessageNames(Class[] classNames) {
diff --git a/core/java/com/android/internal/util/Predicate.java b/core/java/com/android/internal/util/Predicate.java
index bc6d6b3..1b5eaff 100644
--- a/core/java/com/android/internal/util/Predicate.java
+++ b/core/java/com/android/internal/util/Predicate.java
@@ -25,7 +25,10 @@
  * <p/>
  * Implementors of Predicate which may cause side effects upon evaluation are
  * strongly encouraged to state this fact clearly in their API documentation.
+ *
+ * @deprecated Use {@code java.util.function.Predicate} instead.
  */
+@Deprecated
 public interface Predicate<T> {
 
     boolean apply(T t);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index be10608df..d67cef3 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -23,6 +23,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -1495,7 +1497,7 @@
     }
 
     /**
-     * @return number of log records
+     * @return the number of log records currently readable
      */
     public final int getLogRecSize() {
         // mSmHandler can be null if the state machine has quit.
@@ -1505,6 +1507,17 @@
     }
 
     /**
+     * @return the number of log records we can store
+     */
+    @VisibleForTesting
+    public final int getLogRecMaxSize() {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return 0;
+        return smh.mLogRecords.mMaxSize;
+    }
+
+    /**
      * @return the total number of records processed
      */
     public final int getLogRecCount() {
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 4fd19c3..7e91537 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -26,8 +26,7 @@
 import android.widget.HeaderViewListAdapter;
 
 import java.util.ArrayList;
-
-import com.android.internal.util.Predicate;
+import java.util.function.Predicate;
 
 public class WatchHeaderListView extends ListView {
     private View mTopPanel;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 24c8bfb..a9ca12b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -84,6 +84,7 @@
     android_os_MessageQueue.cpp \
     android_os_Parcel.cpp \
     android_os_SELinux.cpp \
+    android_os_seccomp.cpp \
     android_os_SystemClock.cpp \
     android_os_SystemProperties.cpp \
     android_os_Trace.cpp \
@@ -215,6 +216,9 @@
     external/freetype/include
 # TODO: clean up Minikin so it doesn't need the freetype include
 
+LOCAL_STATIC_LIBRARIES := \
+    libseccomp_policy \
+
 LOCAL_SHARED_LIBRARIES := \
     libmemtrack \
     libandroidfw \
@@ -269,6 +273,7 @@
     libhidlbase \
     libhidltransport \
     libhwbinder \
+    libvintf \
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 07392c4..00d9a96 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -163,6 +163,7 @@
 extern int register_android_os_MessageQueue(JNIEnv* env);
 extern int register_android_os_Parcel(JNIEnv* env);
 extern int register_android_os_SELinux(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);
 extern int register_android_os_Trace(JNIEnv* env);
@@ -218,7 +219,7 @@
     gCurRuntime->onStarted();
 }
 
-static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
+static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
 {
     gCurRuntime->onZygoteInit();
 }
@@ -232,19 +233,27 @@
 /*
  * JNI registration.
  */
-static const JNINativeMethod gMethods[] = {
-    { "nativeFinishInit", "()V",
-        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
-    { "nativeZygoteInit", "()V",
-        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
-    { "nativeSetExitWithoutCleanup", "(Z)V",
-        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
-};
 
 int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
 {
+    const JNINativeMethod methods[] = {
+        { "nativeFinishInit", "()V",
+            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
+        { "nativeSetExitWithoutCleanup", "(Z)V",
+            (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
+    };
     return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
-        gMethods, NELEM(gMethods));
+        methods, NELEM(methods));
+}
+
+int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
+{
+    const JNINativeMethod methods[] = {
+        { "nativeZygoteInit", "()V",
+            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
+    };
+    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
+        methods, NELEM(methods));
 }
 
 // ----------------------------------------------------------------------
@@ -1273,6 +1282,7 @@
 
 static const RegJNIRec gRegJNI[] = {
     REG_JNI(register_com_android_internal_os_RuntimeInit),
+    REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_android_os_SystemClock),
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
@@ -1366,6 +1376,7 @@
     REG_JNI(register_android_os_FileObserver),
     REG_JNI(register_android_os_MessageQueue),
     REG_JNI(register_android_os_SELinux),
+    REG_JNI(register_android_os_seccomp),
     REG_JNI(register_android_os_Trace),
     REG_JNI(register_android_os_UEventObserver),
     REG_JNI(register_android_net_LocalSocketImpl),
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index cbe2bba..a758489 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1012,9 +1012,8 @@
     ALOGD("Native heap dump complete.\n");
 }
 
-
-static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
-    jint pid, jstring fileName)
+static void android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
+    jint pid, jstring fileName, jint timeoutSecs)
 {
     if (fileName == NULL) {
         jniThrowNullPointerException(env, "file == null");
@@ -1028,17 +1027,13 @@
         env->ReleaseStringCritical(fileName, str);
     }
 
-    int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666);  /* -rw-rw-rw- */
+    int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 0666);
     if (fd < 0) {
         fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
         return;
     }
 
-    if (lseek(fd, 0, SEEK_END) < 0) {
-        fprintf(stderr, "lseek: %s\n", strerror(errno));
-    } else {
-        dump_backtrace_to_file(pid, fd);
-    }
+    dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
 
     close(fd);
 }
@@ -1083,8 +1078,8 @@
             (void*)android_os_Debug_getProxyObjectCount },
     { "getBinderDeathObjectCount", "()I",
             (void*)android_os_Debug_getDeathObjectCount },
-    { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
-            (void*)android_os_Debug_dumpNativeBacktraceToFile },
+    { "dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)V",
+            (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout },
     { "getUnreachableMemory", "(IZ)Ljava/lang/String;",
             (void*)android_os_Debug_getUnreachableMemory },
 };
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index d35ffbb..c1d4251 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -33,6 +33,7 @@
 #include <hidl/HidlTransportSupport.h>
 #include <hwbinder/ProcessState.h>
 #include <nativehelper/ScopedLocalRef.h>
+#include <vintf/parse_string.h>
 
 #include "core_jni_helpers.h"
 
@@ -127,18 +128,23 @@
         uint32_t flags,
         TransactCallback callback) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    bool isOneway = (flags & TF_ONE_WAY) != 0;
+    ScopedLocalRef<jobject> replyObj(env, nullptr);
+    sp<JHwParcel> replyContext = nullptr;
 
     ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
             const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
 
-    ScopedLocalRef<jobject> replyObj(env, JHwParcel::NewObject(env));
 
-    sp<JHwParcel> replyContext =
-        JHwParcel::GetNativeContext(env, replyObj.get());
+    if (!isOneway) {
+        replyObj.reset(JHwParcel::NewObject(env));
 
-    replyContext->setParcel(reply, false /* assumeOwnership */);
-    replyContext->setTransactCallback(callback);
+        replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
+
+        replyContext->setParcel(reply, false /* assumeOwnership */);
+        replyContext->setTransactCallback(callback);
+    }
 
     env->CallVoidMethod(
             mObject,
@@ -166,27 +172,29 @@
 
     status_t err = OK;
 
-    if (!replyContext->wasSent()) {
-        // The implementation never finished the transaction.
-        err = UNKNOWN_ERROR;  // XXX special error code instead?
+    if (!isOneway) {
+        if (!replyContext->wasSent()) {
+            // The implementation never finished the transaction.
+            err = UNKNOWN_ERROR;  // XXX special error code instead?
 
-        reply->setDataPosition(0 /* pos */);
+            reply->setDataPosition(0 /* pos */);
+        }
+
+        // Release all temporary storage now that scatter-gather data
+        // has been consolidated, either by calling the TransactCallback,
+        // if wasSent() == true or clearing the reply parcel (setDataOffset above).
+        replyContext->getStorage()->release(env);
+
+        // We cannot permanently pass ownership of "data" and "reply" over to their
+        // Java object wrappers (we don't own them ourselves).
+        replyContext->setParcel(
+                NULL /* parcel */, false /* assumeOwnership */);
+
     }
 
-    // Release all temporary storage now that scatter-gather data
-    // has been consolidated, either by calling the TransactCallback,
-    // if wasSent() == true or clearing the reply parcel (setDataOffset above).
-    replyContext->getStorage()->release(env);
-
-    // We cannot permanently pass ownership of "data" and "reply" over to their
-    // Java object wrappers (we don't own them ourselves).
-
     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
             NULL /* parcel */, false /* assumeOwnership */);
 
-    replyContext->setParcel(
-            NULL /* parcel */, false /* assumeOwnership */);
-
     return err;
 }
 
@@ -293,6 +301,8 @@
         jstring ifaceNameObj,
         jstring serviceNameObj) {
 
+    using ::android::vintf::operator<<;
+
     if (ifaceNameObj == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
         return NULL;
@@ -310,27 +320,41 @@
         return NULL;
     }
 
-    const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
-    if (ifaceName == NULL) {
+    const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
+    if (ifaceNameCStr == NULL) {
         return NULL; // XXX exception already pending?
     }
-    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
-    if (serviceName == NULL) {
-        env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+    std::string ifaceName(ifaceNameCStr);
+    env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
+    ::android::hardware::hidl_string ifaceNameHStr;
+    ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());
+
+    const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
+    if (serviceNameCStr == NULL) {
         return NULL; // XXX exception already pending?
     }
+    std::string serviceName(serviceNameCStr);
+    env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
+    ::android::hardware::hidl_string serviceNameHStr;
+    serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());
 
     LOG(INFO) << "Looking for service "
               << ifaceName
               << "/"
               << serviceName;
 
-    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
+    ::android::vintf::Transport transport =
+            ::android::hardware::getTransport(ifaceName);
+    if (   transport != ::android::vintf::Transport::EMPTY
+        && transport != ::android::vintf::Transport::HWBINDER) {
+        LOG(ERROR) << "service " << ifaceName << " declares transport method "
+                   << transport << " but framework expects "
+                   << ::android::vintf::Transport::HWBINDER;
+        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+        return NULL;
+    }
 
-    env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
-    ifaceName = NULL;
-    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
-    serviceName = NULL;
+    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);
 
     if (!ret.isOk()) {
         signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index b2dee06..8590ecf 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -382,7 +382,7 @@
     s = nullptr;
 
     hidl_string tmp;
-    tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
+    tmp.setToExternal(static_cast<const char *>(subBlob->data()), size - 1);
 
     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
     blob->write(offset, &tmp, sizeof(tmp));
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
new file mode 100644
index 0000000..dd5622d
--- /dev/null
+++ b/core/jni/android_os_seccomp.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include "core_jni_helpers.h"
+#include "JniConstants.h"
+#include "utils/Log.h"
+#include "seccomp_policy.h"
+
+static void Seccomp_setPolicy(JNIEnv* /*env*/) {
+    if (!set_seccomp_filter()) {
+        ALOGE("Failed to set seccomp policy - killing");
+        exit(1);
+    }
+}
+
+static const JNINativeMethod method_table[] = {
+    NATIVE_METHOD(Seccomp, setPolicy, "()V"),
+};
+
+namespace android {
+
+int register_android_os_seccomp(JNIEnv* env) {
+    return android::RegisterMethodsOrDie(env, "android/os/Seccomp",
+                                         method_table, NELEM(method_table));
+}
+
+}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index b57f2362..a03d3c5 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -252,25 +252,26 @@
             if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
                 // This task wants to stay at background
                 // update its cpuset so it doesn't only run on bg core(s)
-#ifdef ENABLE_CPUSETS
-                int err = set_cpuset_policy(t_pid, sp);
-                if (err != NO_ERROR) {
-                    signalExceptionForGroupError(env, -err, t_pid);
-                    break;
+                if (cpusets_enabled()) {
+                    int err = set_cpuset_policy(t_pid, sp);
+                    if (err != NO_ERROR) {
+                        signalExceptionForGroupError(env, -err, t_pid);
+                        break;
+                    }
                 }
-#endif
                 continue;
             }
         }
         int err;
-#ifdef ENABLE_CPUSETS
-        // set both cpuset and cgroup for general threads
-        err = set_cpuset_policy(t_pid, sp);
-        if (err != NO_ERROR) {
-            signalExceptionForGroupError(env, -err, t_pid);
-            break;
+
+        if (cpusets_enabled()) {
+            // set both cpuset and cgroup for general threads
+            err = set_cpuset_policy(t_pid, sp);
+            if (err != NO_ERROR) {
+                signalExceptionForGroupError(env, -err, t_pid);
+                break;
+            }
         }
-#endif
 
         err = set_sched_policy(t_pid, sp);
         if (err != NO_ERROR) {
@@ -291,7 +292,6 @@
     return (int) sp;
 }
 
-#ifdef ENABLE_CPUSETS
 /** Sample CPUset list format:
  *  0-3,4,6-8
  */
@@ -367,7 +367,6 @@
     }
     return;
 }
-#endif
 
 
 /**
@@ -376,22 +375,21 @@
  * them in the passed in cpu_set_t
  */
 void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) {
-#ifdef ENABLE_CPUSETS
-    int i;
-    cpu_set_t tmp_set;
-    get_cpuset_cores_for_policy(policy, cpu_set);
-    for (i = 0; i < SP_CNT; i++) {
-        if ((SchedPolicy) i == policy) continue;
-        get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
-        // First get cores exclusive to one set or the other
-        CPU_XOR(&tmp_set, cpu_set, &tmp_set);
-        // Then get the ones only in cpu_set
-        CPU_AND(cpu_set, cpu_set, &tmp_set);
+    if (cpusets_enabled()) {
+        int i;
+        cpu_set_t tmp_set;
+        get_cpuset_cores_for_policy(policy, cpu_set);
+        for (i = 0; i < SP_CNT; i++) {
+            if ((SchedPolicy) i == policy) continue;
+            get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
+            // First get cores exclusive to one set or the other
+            CPU_XOR(&tmp_set, cpu_set, &tmp_set);
+            // Then get the ones only in cpu_set
+            CPU_AND(cpu_set, cpu_set, &tmp_set);
+        }
+    } else {
+        CPU_ZERO(cpu_set);
     }
-#else
-    (void) policy;
-    CPU_ZERO(cpu_set);
-#endif
     return;
 }
 
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index c7998a1..1c6ead0 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -111,11 +111,12 @@
 }
 
 static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
-        NativeInputChannel* nativeInputChannel) {
+        std::unique_ptr<NativeInputChannel> nativeInputChannel) {
     jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
             gInputChannelClassInfo.ctor);
     if (inputChannelObj) {
-        android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+        android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
+                 nativeInputChannel.release());
     }
     return inputChannelObj;
 }
@@ -143,13 +144,13 @@
     }
 
     jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
-            new NativeInputChannel(serverChannel));
+            std::make_unique<NativeInputChannel>(serverChannel));
     if (env->ExceptionCheck()) {
         return NULL;
     }
 
     jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
-            new NativeInputChannel(clientChannel));
+            std::make_unique<NativeInputChannel>(clientChannel));
     if (env->ExceptionCheck()) {
         return NULL;
     }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 516ab38..3498108 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -247,24 +247,42 @@
 
 static void DropCapabilitiesBoundingSet(JNIEnv* env) {
   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-    // Keep CAP_SYS_PTRACE in our bounding set so crash_dump can gain it.
-    if (i == CAP_SYS_PTRACE) {
-      continue;
-    }
-
     int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
     if (rc == -1) {
       if (errno == EINVAL) {
         ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
               "your kernel is compiled with file capabilities support");
       } else {
+        ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
         RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
       }
     }
   }
 }
 
-static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  if (capget(&capheader, &capdata[0]) == -1) {
+    ALOGE("capget failed: %s", strerror(errno));
+    RuntimeAbort(env, __LINE__, "capget failed");
+  }
+
+  capdata[0].inheritable = inheritable;
+  capdata[1].inheritable = inheritable >> 32;
+
+  if (capset(&capheader, &capdata[0]) == -1) {
+    ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
+    RuntimeAbort(env, __LINE__, "capset failed");
+  }
+}
+
+static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
+                            uint64_t inheritable) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -276,9 +294,12 @@
   capdata[1].effective = effective >> 32;
   capdata[0].permitted = permitted;
   capdata[1].permitted = permitted >> 32;
+  capdata[0].inheritable = inheritable;
+  capdata[1].inheritable = inheritable >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective);
+    ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted,
+          effective, inheritable, strerror(errno));
     RuntimeAbort(env, __LINE__, "capset failed");
   }
 }
@@ -513,6 +534,7 @@
       EnableKeepCapabilities(env);
     }
 
+    SetInheritable(env, permittedCapabilities);
     DropCapabilitiesBoundingSet(env);
 
     bool use_native_bridge = !is_system_server && (instructionSet != NULL)
@@ -585,7 +607,7 @@
         }
     }
 
-    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+    SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities);
 
     SetSchedulerPolicy(env);
 
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index c4e8e9c..40c9941 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -45,7 +45,7 @@
             android:textColor="?attr/colorAccent"
             android:gravity="center_vertical"
             android:layout_alignParentTop="true"
-            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"
             android:singleLine="true" />
 
         <TextView
@@ -59,7 +59,7 @@
             android:paddingEnd="?attr/dialogPreferredPadding"
             android:paddingTop="8dp"
             android:layout_below="@id/profile_button"
-            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
             android:paddingBottom="8dp" />
     </RelativeLayout>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4ff78ea..09bf39c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2683,6 +2683,6 @@
     <!-- An array of packages for which notifications cannot be blocked. -->
     <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
 
-    <!-- Component name of the default cell broadcast receiver -->
-    <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+    <!-- Package name of the default cell broadcast receiver -->
+    <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 426d2eb..4231698 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -101,6 +101,8 @@
     <!-- Displayed when the user dialed an MMI code whose function
          could not be performed because FDN is enabled. This will be displayed in a toast. -->
     <string name="mmiFdnError">Operation is restricted to fixed dialing numbers only.</string>
+    <!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
+    <string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
 
     <!-- Displayed when a phone feature such as call barring was activated. -->
     <string name="serviceEnabled">Service was enabled.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bdac134..dbeda0b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -725,6 +725,7 @@
   <java-symbol type="string" name="mmiComplete" />
   <java-symbol type="string" name="mmiError" />
   <java-symbol type="string" name="mmiFdnError" />
+  <java-symbol type="string" name="mmiErrorWhileRoaming" />
   <java-symbol type="string" name="month_day_year" />
   <java-symbol type="string" name="more_item_label" />
   <java-symbol type="string" name="needPuk" />
@@ -2740,5 +2741,5 @@
 <!-- Network Recommendation -->
   <java-symbol type="array" name="config_networkRecommendationPackageNames" />
 
-  <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+  <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
 </resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 33a9265..8ac5252 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -21,6 +21,7 @@
 	$(call all-java-files-under, DisabledTestApp/src) \
 	$(call all-java-files-under, EnabledTestApp/src)
 
+LOCAL_DX_FLAGS := --core-library
 LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
 LOCAL_STATIC_JAVA_LIBRARIES := \
     core-tests-support \
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 836ede6..14b032e 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -31,9 +31,28 @@
 
 LOCAL_JAVACFLAGS := -nowarn
 
+mainDexList:= \
+    $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+	echo "com/android/multidexlegacyandexception/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 2915914..208eceb 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -29,13 +29,32 @@
 
 LOCAL_DEX_PREOPT := false
 
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+	echo "com/android/multidexlegacytestapp/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
+
 ## The application with a full main dex
 include $(CLEAR_VARS)
 
@@ -51,9 +70,28 @@
 
 LOCAL_DEX_PREOPT := false
 
+mainDexList2:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList2): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+	echo "com/android/multidexlegacytestapp/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList2)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 2732372..99bcd6c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -26,8 +26,20 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
 
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
 
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index b4a666f..1c7d807 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -28,9 +28,28 @@
 
 LOCAL_DEX_PREOPT := false
 
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index f38bd4f..b77cf31 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -28,9 +28,28 @@
 
 LOCAL_DEX_PREOPT := false
 
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 5bc2c95..3631626 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -26,11 +26,31 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
 
+mainDexList:= \
+	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
 LOCAL_DEX_PREOPT := false
 
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
 LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
     -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+	$(hide) mkdir -p $(dir $@)
+	$(MAINDEXCLASSES) $< 1>$@
+	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
+
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index e16c367..4c2e224 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := \
 	$(call all-java-files-under, src)
 
+LOCAL_DX_FLAGS := --core-library
 LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
 LOCAL_JAVA_LIBRARIES := android.test.runner
 LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0a814f3..05fec5e 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -50,5 +50,5 @@
 LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
 LOCAL_MODULE := legacy-performance-test-hostdex
 
-include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
 endif  # HOST_OS == linux
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a7cbf5e..bf9423c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -167,7 +167,7 @@
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
     hwui_c_includes += \
-        $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) \
+        $(call intermediates-dir-for,STATIC_LIBRARIES,TARGET,) \
         frameworks/rs/cpp \
         frameworks/rs
 endif
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
index dca78b3..8dae273 100644
--- a/libs/hwui/hwui_static_deps.mk
+++ b/libs/hwui/hwui_static_deps.mk
@@ -28,5 +28,5 @@
     libandroidfw
 
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
-    LOCAL_SHARED_LIBRARIES += libRS libRScpp
+    LOCAL_SHARED_LIBRARIES += libRScpp
 endif
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
new file mode 100644
index 0000000..a438afd
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+
+class ShadowShaderAnimation;
+
+static TestScene::Registrar _ShadowShader(TestScene::Info{
+    "shadowshader",
+    "A set of overlapping shadowed areas with simple tessellation useful for"
+    " benchmarking shadow shader performance.",
+    TestScene::simpleCreateScene<ShadowShaderAnimation>
+});
+
+class ShadowShaderAnimation : public TestScene {
+public:
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas.insertReorderBarrier(true);
+
+        int outset = 50;
+        for (int i = 0; i < 10; i++) {
+            sp<RenderNode> card = createCard(outset, outset,
+                    width - (outset * 2), height - (outset * 2));
+            canvas.drawRenderNode(card.get());
+            cards.push_back(card);
+        }
+
+        canvas.insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 10;
+        for (size_t ci = 0; ci < cards.size(); ci++) {
+            cards[ci]->mutateStagingProperties().setTranslationX(curFrame);
+            cards[ci]->mutateStagingProperties().setTranslationY(curFrame);
+            cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        }
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        return TestUtils::createNode(x, y, x + width, y + height,
+                [width, height](RenderProperties& props, TestCanvas& canvas) {
+            props.setElevation(1000);
+
+            // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline
+            // to signal contents aren't opaque (not necessary though, as elevation is so high, no
+            // inner content to cut out)
+            props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f);
+            props.mutableOutline().setShouldClip(false);
+
+            // don't draw anything to card's canvas - we just want the shadow
+        });
+    }
+};
diff --git a/native/android/Android.mk b/native/android/Android.mk
index da4e4ba..1f69df1 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -1,6 +1,8 @@
 BASE_PATH := $(call my-dir)
 LOCAL_PATH:= $(call my-dir)
 
+common_cflags := -Wall -Werror -Wunused -Wunreachable-code
+
 include $(CLEAR_VARS)
 
 # our source files
@@ -42,6 +44,23 @@
 
 LOCAL_MODULE := libandroid
 
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += $(common_cflags)
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Network library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libandroid_net
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SRC_FILES:= \
+    net.c \
+
+LOCAL_SHARED_LIBRARIES := \
+    libnetd_client \
+
+LOCAL_C_INCLUDES += \
+    frameworks/base/native/include \
+    bionic/libc/dns/include \
+    system/netd/include \
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index acee5dd..3831cf7 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -658,6 +658,11 @@
          */
         byte[] sendData = new byte[totalLength];
         int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
+        if (maxRxLength > mMaxPacketLength) {
+            if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
+                    " and MaxNegotiated from Client: " + mMaxPacketLength);
+            maxRxLength = mMaxPacketLength;
+        }
         sendData[0] = (byte)code;
         sendData[1] = length[2];
         sendData[2] = length[3];
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e2080b0..d910920 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -31,7 +31,7 @@
     <application android:label="@string/app_name" >
         <receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
             <intent-filter>
-                <action android:name="android.intent.action.CARRIER_SIGNAL_REDIRECTED" />
+                <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
             </intent-filter>
         </receiver>
         <activity android:name="com.android.carrierdefaultapp.CaptivePortalLaunchActivity"
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 9d44a6d..29035ab 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -12,6 +12,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
 # Supplies material design components, e.g. Snackbar.
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-transition
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
 LOCAL_STATIC_JAVA_LIBRARIES += guava
 
@@ -22,6 +23,7 @@
 LOCAL_RESOURCE_DIR += \
   frameworks/support/v7/appcompat/res \
   frameworks/support/design/res \
+  frameworks/support/transition/res \
   frameworks/support/v7/recyclerview/res
 
 # Again, required to pull in appcompat resources.  See abovementioned demo code.
@@ -29,6 +31,7 @@
   --auto-add-overlay \
   --extra-packages android.support.v7.appcompat \
   --extra-packages android.support.design \
+  --extra-packages android.support.transition \
   --extra-packages android.support.v7.recyclerview
 
 LOCAL_JACK_FLAGS := \
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 859763b..08b82d0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -20,33 +20,14 @@
 import android.provider.DocumentsContract.Document;
 
 import com.android.documentsui.model.DocumentInfo;
-import com.android.internal.util.Predicate;
 
-public class MimePredicate implements Predicate<DocumentInfo> {
-    private final String[] mFilters;
-
-    private static final String APK_TYPE = "application/vnd.android.package-archive";
+public class MimePredicate {
     /**
      * MIME types that are visual in nature. For example, they should always be
      * shown as thumbnails in list mode.
      */
     public static final String[] VISUAL_MIMES = new String[] { "image/*", "video/*" };
 
-    public MimePredicate(String[] filters) {
-        mFilters = filters;
-    }
-
-    @Override
-    public boolean apply(DocumentInfo doc) {
-        if (doc.isDirectory()) {
-            return true;
-        }
-        if (mimeMatches(mFilters, doc.mimeType)) {
-            return true;
-        }
-        return false;
-    }
-
     public static boolean mimeMatches(String[] filters, String[] tests) {
         if (tests == null) {
             return false;
@@ -97,10 +78,6 @@
         }
     }
 
-    public static boolean isApkType(@Nullable String mimeType) {
-        return APK_TYPE.equals(mimeType);
-    }
-
     public static boolean isDirectoryType(@Nullable String mimeType) {
         return Document.MIME_TYPE_DIR.equals(mimeType);
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 6ef9154..6bf8ccc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -39,7 +39,6 @@
 
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
-import com.android.internal.util.Predicate;
 
 import com.google.android.collect.Sets;
 
@@ -47,6 +46,7 @@
 
 import java.io.IOException;
 import java.util.Set;
+import java.util.function.Predicate;
 
 public class RecentsProvider extends ContentProvider {
     private static final String TAG = "RecentsProvider";
@@ -269,7 +269,7 @@
 
             purgeByAuthority(new Predicate<String>() {
                 @Override
-                public boolean apply(String authority) {
+                public boolean test(String authority) {
                     // Purge unknown authorities
                     return !knownAuth.contains(authority);
                 }
@@ -290,7 +290,7 @@
             if (!packageAuth.isEmpty()) {
                 purgeByAuthority(new Predicate<String>() {
                     @Override
-                    public boolean apply(String authority) {
+                    public boolean test(String authority) {
                         // Purge authority matches
                         return packageAuth.contains(authority);
                     }
@@ -320,7 +320,7 @@
                             cursor.getColumnIndex(RecentColumns.STACK));
                     DurableUtils.readFromArray(rawStack, stack);
 
-                    if (stack.root != null && predicate.apply(stack.root.authority)) {
+                    if (stack.root != null && predicate.test(stack.root.authority)) {
                         final String key = getCursorString(cursor, RecentColumns.KEY);
                         db.delete(TABLE_RECENT, RecentColumns.KEY + "=?", new String[] { key });
                     }
@@ -336,7 +336,7 @@
         try {
             while (cursor.moveToNext()) {
                 final String authority = getCursorString(cursor, StateColumns.AUTHORITY);
-                if (predicate.apply(authority)) {
+                if (predicate.test(authority)) {
                     db.delete(TABLE_STATE, StateColumns.AUTHORITY + "=?", new String[] {
                             authority });
                     if (DEBUG) Log.d(TAG, "Purged state for " + authority);
@@ -354,7 +354,7 @@
                             cursor.getColumnIndex(ResumeColumns.STACK));
                     DurableUtils.readFromArray(rawStack, stack);
 
-                    if (stack.root != null && predicate.apply(stack.root.authority)) {
+                    if (stack.root != null && predicate.test(stack.root.authority)) {
                         final String packageName = getCursorString(
                                 cursor, ResumeColumns.PACKAGE_NAME);
                         db.delete(TABLE_RESUME, ResumeColumns.PACKAGE_NAME + "=?",
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index ec6af2f..fbf3782 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -5,7 +5,10 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-documents-archive
+LOCAL_STATIC_JAVA_LIBRARIES :=  \
+    android-support-documents-archive \
+    android-support-annotations
+
 LOCAL_PACKAGE_NAME := ExternalStorageProvider
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/PrintSpooler/res/layout/no_print_services_message.xml b/packages/PrintSpooler/res/layout/no_print_services_message.xml
new file mode 100644
index 0000000..7872658
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/no_print_services_message.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/listPreferredItemHeightSmall"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal"
+    android:gravity="start|center_vertical">
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="32dip">
+            <HorizontalScrollView
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content">
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textAppearance="?android:attr/textAppearanceListItem"
+                    android:text="@string/print_no_print_services"
+                    android:scrollHorizontally="true"
+                    android:singleLine="true" />
+            </HorizontalScrollView>
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index c06e849..72004ef 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.Loader;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.DataSetObserver;
 import android.net.Uri;
@@ -95,20 +96,39 @@
      */
     private RecommendedServicesAdapter mRecommendedServicesAdapter;
 
+    private static final String PKG_NAME_VENDING = "com.android.vending";
+    private boolean mHasVending;
+    private NoPrintServiceMessageAdapter mNoPrintServiceMessageAdapter;
+
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.add_printer_activity);
 
+        try {
+            getPackageManager().getPackageInfo(PKG_NAME_VENDING, 0);
+            mHasVending = true;
+        } catch (PackageManager.NameNotFoundException e) {
+            mHasVending = false;
+        }
         mEnabledServicesAdapter = new EnabledServicesAdapter();
         mDisabledServicesAdapter = new DisabledServicesAdapter();
-        mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+        if (mHasVending) {
+            mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+        } else {
+            mNoPrintServiceMessageAdapter = new NoPrintServiceMessageAdapter();
+        }
 
         ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
         adapterList.add(mEnabledServicesAdapter);
-        adapterList.add(mRecommendedServicesAdapter);
+        if (mHasVending) {
+            adapterList.add(mRecommendedServicesAdapter);
+        }
         adapterList.add(mDisabledServicesAdapter);
+        if (!mHasVending) {
+            adapterList.add(mNoPrintServiceMessageAdapter);
+        }
 
         setListAdapter(new CombinedAdapter(adapterList));
 
@@ -119,8 +139,10 @@
 
         getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
         getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
-        getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
-                new PrintServicePrintServiceRecommendationLoaderCallbacks());
+        if (mHasVending) {
+            getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
+                    new PrintServicePrintServiceRecommendationLoaderCallbacks());
+        }
         getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
     }
 
@@ -162,7 +184,11 @@
                     mDisabledServicesAdapter.updateData(data);
                     break;
                 case LOADER_ID_ALL_SERVICES:
-                    mRecommendedServicesAdapter.updateInstalledServices(data);
+                    if (mHasVending) {
+                        mRecommendedServicesAdapter.updateInstalledServices(data);
+                    } else {
+                        mNoPrintServiceMessageAdapter.updateInstalledServices(data);
+                    }
                 default:
                     // not reached
             }
@@ -179,7 +205,11 @@
                         mDisabledServicesAdapter.updateData(null);
                         break;
                     case LOADER_ID_ALL_SERVICES:
-                        mRecommendedServicesAdapter.updateInstalledServices(null);
+                        if (mHasVending) {
+                            mRecommendedServicesAdapter.updateInstalledServices(null);
+                        } else {
+                            mNoPrintServiceMessageAdapter.updateInstalledServices(null);
+                        }
                         break;
                     default:
                         // not reached
@@ -788,4 +818,61 @@
             filterRecommendations();
         }
     }
+
+    private class NoPrintServiceMessageAdapter extends ActionAdapter {
+        private boolean mHasPrintService;
+
+        void updateInstalledServices(@Nullable List<PrintServiceInfo> services) {
+            if (services == null || services.isEmpty()) {
+                mHasPrintService = false;
+            } else {
+                mHasPrintService = true;
+            }
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getCount() {
+            return mHasPrintService ? 0 : 1;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 1;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            return 0;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return null;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = getLayoutInflater().inflate(R.layout.no_print_services_message,
+                    parent, false);
+            }
+            return convertView;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return position != 0;
+        }
+
+        @Override
+        public void performAction(@IntRange(from = 0) int position) {
+            return;
+        }
+    }
 }
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index cf0ba6c..0815534 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -24,5 +24,9 @@
 LOCAL_STATIC_JAVA_LIBRARIES += \
     android-support-annotations \
     android-support-v4 \
+    android-support-v7-appcompat \
+    android-support-v7-preference \
+    android-support-v7-recyclerview \
+    android-support-v14-preference \
     SettingsLib
 endif
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3627c29..064059b 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -57,6 +57,8 @@
     <string name="wifi_disabled_generic">Disabled</string>
     <!-- Status for networked disabled from a DNS or DHCP failure -->
     <string name="wifi_disabled_network_failure">IP Configuration Failure</string>
+    <!-- Status for networks disabled by the network recommendation provider -->
+    <string name="wifi_disabled_by_recommendation_provider">Not connected due to low quality network</string>
     <!-- Status for networked disabled from a wifi association failure -->
     <string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
     <!-- Status for networks disabled from authentication failure (wrong password
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 252aaab..6166cd8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -422,7 +422,8 @@
             // This is the active connection on non-passpoint network
             summary.append(getSummary(mContext, getDetailedState(),
                     mInfo != null && mInfo.isEphemeral()));
-        } else if (config != null && config.isPasspoint()) {
+        } else if (config != null && config.isPasspoint()
+                && config.getNetworkSelectionStatus().isNetworkEnabled()) {
             String format = mContext.getString(R.string.available_via_passpoint);
             summary.append(String.format(format, config.providerFriendlyName));
         } else if (config != null && config.hasNoInternetAccess()) {
@@ -445,6 +446,8 @@
                     summary.append(mContext.getString(R.string.wifi_disabled_generic));
                     break;
             }
+        } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
+            summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
             summary.append(mContext.getString(R.string.wifi_not_in_range));
         } else { // In range, not disabled.
@@ -682,11 +685,7 @@
     }
 
     void loadConfig(WifiConfiguration config) {
-        if (config.isPasspoint())
-            ssid = config.providerFriendlyName;
-        else
-            ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
-
+        ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
         bssid = config.BSSID;
         security = getSecurity(config);
         networkId = config.networkId;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 7d279eb..3435d1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -344,29 +344,22 @@
                 }
                 AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
                 if (mLastInfo != null && mLastNetworkInfo != null) {
-                    if (config.isPasspoint() == false) {
-                        accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
-                    }
+                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                 }
                 if (mIncludeSaved) {
-                    if (!config.isPasspoint() || mIncludePasspoints) {
-                        // If saved network not present in scan result then set its Rssi to MAX_VALUE
-                        boolean apFound = false;
-                        for (ScanResult result : results) {
-                            if (result.SSID.equals(accessPoint.getSsidStr())) {
-                                apFound = true;
-                                break;
-                            }
+                    // If saved network not present in scan result then set its Rssi to MAX_VALUE
+                    boolean apFound = false;
+                    for (ScanResult result : results) {
+                        if (result.SSID.equals(accessPoint.getSsidStr())) {
+                            apFound = true;
+                            break;
                         }
-                        if (!apFound) {
-                            accessPoint.setRssi(Integer.MAX_VALUE);
-                        }
-                        accessPoints.add(accessPoint);
                     }
-
-                    if (config.isPasspoint() == false) {
-                        apMap.put(accessPoint.getSsidStr(), accessPoint);
+                    if (!apFound) {
+                        accessPoint.setRssi(Integer.MAX_VALUE);
                     }
+                    accessPoints.add(accessPoint);
+                    apMap.put(accessPoint.getSsidStr(), accessPoint);
                 } else {
                     // If we aren't using saved networks, drop them into the cache so that
                     // we have access to their saved info.
@@ -397,20 +390,16 @@
                     }
 
                     if (result.isPasspointNetwork()) {
+                        // Retrieve a WifiConfiguration for a Passpoint provider that matches
+                        // the given ScanResult.  This is used for showing that a given AP
+                        // (ScanResult) is available via a Passpoint provider (provider friendly
+                        // name).
                         WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result);
                         if (config != null) {
                             accessPoint.update(config);
                         }
                     }
 
-                    if (mLastInfo != null && mLastInfo.getBSSID() != null
-                            && mLastInfo.getBSSID().equals(result.BSSID)
-                            && connectionConfig != null && connectionConfig.isPasspoint()) {
-                        /* This network is connected via this passpoint config */
-                        /* SSID match is not going to work for it; so update explicitly */
-                        accessPoint.update(connectionConfig);
-                    }
-
                     accessPoints.add(accessPoint);
                     apMap.put(accessPoint.getSsidStr(), accessPoint);
                 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 227d0e9..4f7a826 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -41,6 +41,7 @@
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.MANAGE_USB" />
     <!-- System tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
new file mode 100644
index 0000000..7e6e09b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
new file mode 100644
index 0000000..b7b6f0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
new file mode 100644
index 0000000..910c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
new file mode 100644
index 0000000..666127b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.41dp"
+        android:height="17dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
new file mode 100644
index 0000000..eeba030
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.41dp"
+        android:height="17dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="in"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
new file mode 100644
index 0000000..d577d1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="18.41dp"
+        android:height="17dp"
+        android:viewportWidth="26.0"
+        android:viewportHeight="24.0">
+    <path
+        android:name="out"
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index a20ec8e..f597785 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -43,4 +43,10 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         />
+    <ImageView
+        android:id="@+id/mobile_inout"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:visibility="gone"
+        />
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index d17601c..f0bfb92 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -70,6 +70,11 @@
             android:layout_width="wrap_content"
             android:alpha="0.0"
             />
+        <ImageView
+            android:id="@+id/wifi_inout"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            />
     </FrameLayout>
     <View
         android:id="@+id/wifi_signal_spacer"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 484e008..2fd62f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -232,6 +232,8 @@
         i.setPackage(mComponent.getPackageName());
         i = resolveIntent(i);
         if (i != null) {
+            i.putExtra(TileService.EXTRA_COMPONENT, mComponent);
+            i.putExtra(TileService.EXTRA_STATE, mTile.getState());
             return i;
         }
         return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 016c4b7..4b8d7b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -37,6 +38,9 @@
 
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTile<QSTile.AirplaneBooleanState> {
+    static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
+             "com.android.settings", "com.android.settings.TetherSettings"));
+
     private final AnimationIcon mEnable =
             new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
                     R.drawable.ic_hotspot_disable);
@@ -94,7 +98,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+        return new Intent(TETHER_SETTINGS);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 74caa53..d36f572 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -75,6 +75,8 @@
     private boolean mWifiVisible = false;
     private int mWifiStrengthId = 0;
     private int mLastWifiStrengthId = -1;
+    private int mWifiActivityId = 0;
+    private int mLastWifiActivityId = -1;
     private boolean mIsAirplaneMode = false;
     private int mAirplaneIconId = 0;
     private int mLastAirplaneIconId = -1;
@@ -89,6 +91,7 @@
     ViewGroup mEthernetGroup, mWifiGroup;
     View mNoSimsCombo;
     ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+    ImageView mWifiActivity;
     View mWifiAirplaneSpacer;
     View mWifiSignalSpacer;
     LinearLayout mMobileSignalGroup;
@@ -180,6 +183,7 @@
         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
         mWifiDark       = (ImageView) findViewById(R.id.wifi_signal_dark);
+        mWifiActivity   = (ImageView) findViewById(R.id.wifi_inout);
         mAirplane       = (ImageView) findViewById(R.id.airplane);
         mNoSims         = (ImageView) findViewById(R.id.no_sims);
         mNoSimsDark     = (ImageView) findViewById(R.id.no_sims_dark);
@@ -264,6 +268,10 @@
         mWifiVisible = statusIcon.visible && !mBlockWifi;
         mWifiStrengthId = statusIcon.icon;
         mWifiDescription = statusIcon.contentDescription;
+        mWifiActivityId = activityIn && activityOut ? R.drawable.stat_sys_wifi_inout
+                : activityIn ? R.drawable.stat_sys_wifi_in
+                : activityOut ? R.drawable.stat_sys_wifi_out
+                : 0;
 
         apply();
     }
@@ -282,6 +290,10 @@
         state.mMobileDescription = statusIcon.contentDescription;
         state.mMobileTypeDescription = typeContentDescription;
         state.mIsMobileTypeIconWide = statusType != 0 && isWide;
+        state.mMobileActivityId = activityIn && activityOut ? R.drawable.stat_sys_signal_inout
+                : activityIn ? R.drawable.stat_sys_signal_in
+                : activityOut ? R.drawable.stat_sys_signal_out
+                : 0;
 
         apply();
     }
@@ -404,6 +416,10 @@
             mWifiDark.setImageDrawable(null);
             mLastWifiStrengthId = -1;
         }
+        if (mWifiActivity !=  null) {
+            mWifiActivity.setImageDrawable(null);
+            mLastWifiActivityId = -1;
+        }
 
         for (PhoneState state : mPhoneStates) {
             if (state.mMobile != null) {
@@ -420,6 +436,10 @@
                 state.mMobileType.setImageDrawable(null);
                 state.mLastMobileTypeId = -1;
             }
+            if (state.mMobileActivity != null) {
+                state.mMobileActivity.setImageDrawable(null);
+                state.mLastMobileActivityId = -1;
+            }
         }
 
         if (mAirplane != null) {
@@ -473,6 +493,12 @@
                 setIconForView(mWifiDark, mWifiStrengthId);
                 mLastWifiStrengthId = mWifiStrengthId;
             }
+            if (mWifiActivityId != mLastWifiActivityId) {
+                if (mWifiActivityId != 0) {
+                    setIconForView(mWifiActivity, mWifiActivityId);
+                }
+                mLastWifiActivityId = mWifiActivityId;
+            }
             mWifiGroup.setContentDescription(mWifiDescription);
             mWifiGroup.setVisibility(View.VISIBLE);
         } else {
@@ -484,6 +510,8 @@
                     (mWifiVisible ? "VISIBLE" : "GONE"),
                     mWifiStrengthId));
 
+        mWifiActivity.setVisibility(mWifiActivityId != 0 ? View.VISIBLE : View.GONE);
+
         boolean anyMobileVisible = false;
         int firstMobileTypeId = 0;
         for (PhoneState state : mPhoneStates) {
@@ -560,6 +588,8 @@
         applyDarkIntensity(
                 StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
                 mWifi, mWifiDark);
+        setTint(mWifiActivity,
+                StatusBarIconController.getTint(mTintArea, mWifiActivity, mIconTint));
         applyDarkIntensity(
                 StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
                 mEthernet, mEthernetDark);
@@ -584,14 +614,16 @@
     private class PhoneState {
         private final int mSubId;
         private boolean mMobileVisible = false;
-        private int mMobileStrengthId = 0, mMobileTypeId = 0;
+        private int mMobileStrengthId = 0, mMobileTypeId = 0, mMobileActivityId = 0;
         private int mLastMobileStrengthId = -1;
         private int mLastMobileTypeId = -1;
+        private int mLastMobileActivityId = -1;
         private boolean mIsMobileTypeIconWide;
         private String mMobileDescription, mMobileTypeDescription;
 
         private ViewGroup mMobileGroup;
         private ImageView mMobile, mMobileDark, mMobileType;
+        private ImageView mMobileActivity;
 
         public PhoneState(int subId, Context context) {
             ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -605,6 +637,7 @@
             mMobile         = (ImageView) root.findViewById(R.id.mobile_signal);
             mMobileDark     = (ImageView) root.findViewById(R.id.mobile_signal_dark);
             mMobileType     = (ImageView) root.findViewById(R.id.mobile_type);
+            mMobileActivity = (ImageView) root.findViewById(R.id.mobile_inout);
         }
 
         public boolean apply(boolean isSecondaryIcon) {
@@ -619,6 +652,11 @@
                     mMobileType.setImageResource(mMobileTypeId);
                     mLastMobileTypeId = mMobileTypeId;
                 }
+
+                if (mLastMobileActivityId != mMobileActivityId) {
+                    mMobileActivity.setImageResource(mMobileActivityId);
+                    mLastMobileActivityId = mMobileActivityId;
+                }
                 mMobileGroup.setContentDescription(mMobileTypeDescription
                         + " " + mMobileDescription);
                 mMobileGroup.setVisibility(View.VISIBLE);
@@ -640,6 +678,7 @@
                         (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
 
             mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
+            mMobileActivity.setVisibility(mMobileActivityId != 0 ? View.VISIBLE : View.GONE);
 
             return mMobileVisible;
         }
@@ -699,6 +738,8 @@
                     StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
                     mMobile, mMobileDark);
             setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
+            setTint(mMobileActivity,
+                    StatusBarIconController.getTint(tintArea, mMobileActivity, tint));
         }
     }
 }
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 37e6a2a..9380c45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -690,6 +690,7 @@
             mDemoMode = true;
             mDemoInetCondition = mInetCondition;
             mDemoWifiState = mWifiSignalController.getState();
+            mDemoWifiState.ssid = "DemoMode";
         } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
             if (DEBUG) Log.d(TAG, "Exiting demo mode");
             mDemoMode = false;
@@ -735,6 +736,25 @@
                             : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
                     mDemoWifiState.connected = mDemoWifiState.level >= 0;
                 }
+                String activity = args.getString("activity");
+                if (activity != null) {
+                    switch (activity) {
+                        case "inout":
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_INOUT);
+                            break;
+                        case "in":
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_IN);
+                            break;
+                        case "out":
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_OUT);
+                            break;
+                        default:
+                            mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+                            break;
+                    }
+                } else {
+                    mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+                }
                 mDemoWifiState.enabled = show;
                 mWifiSignalController.notifyListeners();
             }
@@ -797,6 +817,26 @@
                             : Math.min(Integer.parseInt(level), icons[0].length - 1);
                     controller.getState().connected = controller.getState().level >= 0;
                 }
+                String activity = args.getString("activity");
+                if (activity != null) {
+                    controller.getState().dataConnected = true;
+                    switch (activity) {
+                        case "inout":
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+                            break;
+                        case "in":
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
+                            break;
+                        case "out":
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
+                            break;
+                        default:
+                            controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+                            break;
+                    }
+                } else {
+                    controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+                }
                 controller.getState().enabled = show;
                 controller.notifyListeners();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a3197c..1b520b4 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -163,7 +163,7 @@
         intent.putExtra("sims", "1");
         intent.putExtra("nosim", "false");
         intent.putExtra("level", "4");
-        intent.putExtra("datatypel", "");
+        intent.putExtra("datatype", "lte");
         getContext().sendBroadcast(intent);
 
         // Need to send this after so that the sim controller already exists.
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index bf4d88c..51c7e55 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index d8fb7a4..09b41fd 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 junit
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
 
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_CERTIFICATE := platform
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
index 100b0b3b..f8b01cb 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -18,7 +18,7 @@
 
 import android.graphics.Bitmap;
 
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
 
 // BitmapTexture is a texture whose content is specified by a fixed Bitmap.
 //
@@ -34,7 +34,7 @@
 
     public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
         super(hasBorder);
-        Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+        Utils.assertTrue(bitmap != null && !bitmap.isRecycled());
         mContentBitmap = bitmap;
     }
 
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
index 16b2206..b26e9ab 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -16,7 +16,7 @@
 
 package com.android.gallery3d.glrenderer;
 
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
 
 public class GLPaint {
     private float mLineWidth = 1f;
@@ -31,7 +31,7 @@
     }
 
     public void setLineWidth(float width) {
-        Assert.assertTrue(width >= 0);
+        Utils.assertTrue(width >= 0);
         mLineWidth = width;
     }
 
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index f41a979..417102a 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -20,7 +20,7 @@
 import android.graphics.Bitmap.Config;
 import android.opengl.GLUtils;
 
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
 
 import java.util.HashMap;
 
@@ -144,7 +144,7 @@
     }
 
     private void freeBitmap() {
-        Assert.assertTrue(mBitmap != null);
+        Utils.assertTrue(mBitmap != null);
         onFreeBitmap(mBitmap);
         mBitmap = null;
     }
@@ -219,7 +219,7 @@
                 int texWidth = getTextureWidth();
                 int texHeight = getTextureHeight();
 
-                Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+                Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
 
                 // Upload the bitmap to a new texture.
                 mId = canvas.getGLId().generateTexture();
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
new file mode 100644
index 0000000..9aa6490
--- /dev/null
+++ b/proto/src/wifi.proto
@@ -0,0 +1,462 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package clearcut.connectivity;
+
+option java_package = "com.android.server.wifi";
+option java_outer_classname = "WifiMetricsProto";
+
+// The information about the Wifi events.
+message WifiLog {
+
+  // Session information that gets logged for every Wifi connection.
+  repeated ConnectionEvent connection_event = 1;
+
+  // Number of saved networks in the user profile.
+  optional int32 num_saved_networks = 2;
+
+  // Number of open networks in the saved networks.
+  optional int32 num_open_networks = 3;
+
+  // Number of personal networks.
+  optional int32 num_personal_networks = 4;
+
+  // Number of enterprise networks.
+  optional int32 num_enterprise_networks = 5;
+
+  // Does the user have location setting enabled.
+  optional bool is_location_enabled = 6;
+
+  // Does the user have scanning enabled.
+  optional bool is_scanning_always_enabled = 7;
+
+  // Number of times user toggled wifi using the settings menu.
+  optional int32 num_wifi_toggled_via_settings = 8;
+
+  // Number of times user toggled wifi using the airplane menu.
+  optional int32 num_wifi_toggled_via_airplane = 9;
+
+  // Number of networks added by the user.
+  optional int32 num_networks_added_by_user = 10;
+
+  // Number of networks added by applications.
+  optional int32 num_networks_added_by_apps = 11;
+
+  // Number scans that returned empty results.
+  optional int32 num_empty_scan_results = 12;
+
+  // Number scans that returned at least one result.
+  optional int32 num_non_empty_scan_results = 13;
+
+  // Number of scans that were one time.
+  optional int32 num_oneshot_scans = 14;
+
+  // Number of repeated background scans that were scheduled to the chip.
+  optional int32 num_background_scans = 15;
+
+  // Error codes that a scan can result in.
+  enum ScanReturnCode {
+
+    // Return Code is unknown.
+    SCAN_UNKNOWN = 0;
+
+    // Scan was successful.
+    SCAN_SUCCESS = 1;
+
+    // Scan was successfully started, but was interrupted.
+    SCAN_FAILURE_INTERRUPTED = 2;
+
+    //  Scan failed to start because of invalid configuration
+    //  (bad channel, etc).
+    SCAN_FAILURE_INVALID_CONFIGURATION = 3;
+
+    // Could not start a scan because wifi is disabled.
+    FAILURE_WIFI_DISABLED = 4;
+
+  }
+
+  // Mapping of error codes to the number of times that scans resulted
+  // in that error.
+  repeated ScanReturnEntry scan_return_entries = 16;
+
+  message ScanReturnEntry {
+
+     // Return code of the scan.
+     optional ScanReturnCode scan_return_code = 1;
+
+     // Number of entries that were found in the scan.
+     optional int32 scan_results_count = 2;
+  }
+
+  // State of the Wifi.
+  enum WifiState {
+
+    // State is unknown.
+    WIFI_UNKNOWN = 0;
+
+    // Wifi is disabled.
+    WIFI_DISABLED = 1;
+
+    // Wifi is enabled.
+    WIFI_DISCONNECTED = 2;
+
+    // Wifi is enabled and associated with an AP.
+    WIFI_ASSOCIATED = 3;
+  }
+
+  // Mapping of system state to the number of times that scans were requested in
+  // that state
+  repeated WifiSystemStateEntry wifi_system_state_entries = 17;
+
+  message WifiSystemStateEntry {
+
+     // Current WiFi state.
+     optional WifiState wifi_state = 1;
+
+     // Count of scans in state.
+     optional int32 wifi_state_count = 2;
+
+     // Is screen on.
+     optional bool is_screen_on = 3;
+  }
+
+  // Mapping of Error/Success codes to the number of background scans that resulted in it
+  repeated ScanReturnEntry background_scan_return_entries = 18;
+
+  // Mapping of system state to the number of times that Background scans were requested in that
+  // state
+  repeated WifiSystemStateEntry background_scan_request_state = 19;
+
+  // Total number of times the Watchdog of Last Resort triggered, resetting the wifi stack
+  optional int32 num_last_resort_watchdog_triggers = 20;
+
+  // Total number of networks over bad association threshold when watchdog triggered
+  optional int32 num_last_resort_watchdog_bad_association_networks_total = 21;
+
+  // Total number of networks over bad authentication threshold when watchdog triggered
+  optional int32 num_last_resort_watchdog_bad_authentication_networks_total = 22;
+
+  // Total number of networks over bad dhcp threshold when watchdog triggered
+  optional int32 num_last_resort_watchdog_bad_dhcp_networks_total = 23;
+
+  // Total number of networks over bad other threshold when watchdog triggered
+  optional int32 num_last_resort_watchdog_bad_other_networks_total = 24;
+
+  // Total count of networks seen when watchdog triggered
+  optional int32 num_last_resort_watchdog_available_networks_total = 25;
+
+  // Total count of triggers with atleast one bad association network
+  optional int32 num_last_resort_watchdog_triggers_with_bad_association = 26;
+
+  // Total count of triggers with atleast one bad authentication network
+  optional int32 num_last_resort_watchdog_triggers_with_bad_authentication = 27;
+
+  // Total count of triggers with atleast one bad dhcp network
+  optional int32 num_last_resort_watchdog_triggers_with_bad_dhcp = 28;
+
+  // Total count of triggers with atleast one bad other network
+  optional int32 num_last_resort_watchdog_triggers_with_bad_other = 29;
+
+  // Count of times connectivity watchdog confirmed pno is working
+  optional int32 num_connectivity_watchdog_pno_good = 30;
+
+  // Count of times connectivity watchdog found pno not working
+  optional int32 num_connectivity_watchdog_pno_bad = 31;
+
+  // Count of times connectivity watchdog confirmed background scan is working
+  optional int32 num_connectivity_watchdog_background_good = 32;
+
+  // Count of times connectivity watchdog found background scan not working
+  optional int32 num_connectivity_watchdog_background_bad = 33;
+
+  // The time duration represented by this wifi log, from start to end of capture
+  optional int32 record_duration_sec = 34;
+
+  // Counts the occurrences of each individual RSSI poll level
+  repeated RssiPollCount rssi_poll_rssi_count = 35;
+
+  // Total number of times WiFi connected immediately after a Last Resort Watchdog trigger,
+  // without new networks becoming available.
+  optional int32 num_last_resort_watchdog_successes = 36;
+
+  // Total number of saved hidden networks
+  optional int32 num_hidden_networks = 37;
+
+  // Total number of saved passpoint / hotspot 2.0 networks
+  optional int32 num_passpoint_networks = 38;
+
+  // Total number of scan results
+  optional int32 num_total_scan_results = 39;
+
+  // Total number of scan results for open networks
+  optional int32 num_open_network_scan_results = 40;
+
+  // Total number of scan results for personal networks
+  optional int32 num_personal_network_scan_results = 41;
+
+  // Total number of scan results for enterprise networks
+  optional int32 num_enterprise_network_scan_results = 42;
+
+  // Total number of scan results for hidden networks
+  optional int32 num_hidden_network_scan_results = 43;
+
+  // Total number of scan results for hotspot 2.0 r1 networks
+  optional int32 num_hotspot2_r1_network_scan_results = 44;
+
+  // Total number of scan results for hotspot 2.0 r2 networks
+  optional int32 num_hotspot2_r2_network_scan_results = 45;
+
+  // Total number of scans handled by framework (oneshot or otherwise)
+  optional int32 num_scans = 46;
+
+  // Counts the occurrences of each alert reason.
+  repeated AlertReasonCount alert_reason_count = 47;
+
+  // Counts the occurrences of each Wifi score
+  repeated WifiScoreCount wifi_score_count = 48;
+
+  // Histogram of Soft AP Durations
+  repeated SoftApDurationBucket soft_ap_duration = 49;
+
+  // Histogram of Soft AP ReturnCode
+  repeated SoftApReturnCodeCount soft_ap_return_code = 50;
+
+  // Histogram of the delta between scan result RSSI and RSSI polls
+  repeated RssiPollCount rssi_poll_delta_count = 51;
+}
+
+// Information that gets logged for every WiFi connection.
+message RouterFingerPrint {
+
+  enum RoamType {
+
+    // Type is unknown.
+    ROAM_TYPE_UNKNOWN = 0;
+
+    // No roaming - usually happens on a single band (2.4 GHz) router.
+    ROAM_TYPE_NONE = 1;
+
+    // Enterprise router.
+    ROAM_TYPE_ENTERPRISE = 2;
+
+    // DBDC => Dual Band Dual Concurrent essentially a router that
+    // supports both 2.4 GHz and 5 GHz bands.
+    ROAM_TYPE_DBDC = 3;
+  }
+
+  enum Auth {
+
+    // Auth is unknown.
+    AUTH_UNKNOWN = 0;
+
+    // No authentication.
+    AUTH_OPEN = 1;
+
+    // If the router uses a personal authentication.
+    AUTH_PERSONAL = 2;
+
+    // If the router is setup for enterprise authentication.
+    AUTH_ENTERPRISE = 3;
+  }
+
+  enum RouterTechnology {
+
+    // Router is unknown.
+    ROUTER_TECH_UNKNOWN = 0;
+
+    // Router Channel A.
+    ROUTER_TECH_A = 1;
+
+    // Router Channel B.
+    ROUTER_TECH_B = 2;
+
+    // Router Channel G.
+    ROUTER_TECH_G = 3;
+
+    // Router Channel N.
+    ROUTER_TECH_N = 4;
+
+    // Router Channel AC.
+    ROUTER_TECH_AC = 5;
+
+    // When the channel is not one of the above.
+    ROUTER_TECH_OTHER = 6;
+  }
+
+  optional RoamType roam_type = 1;
+
+  // Channel on which the connection takes place.
+  optional int32 channel_info = 2;
+
+  // DTIM setting of the router.
+  optional int32 dtim = 3;
+
+  // Authentication scheme of the router.
+  optional Auth authentication = 4;
+
+  // If the router is hidden.
+  optional bool hidden = 5;
+
+  // Channel information.
+  optional RouterTechnology router_technology = 6;
+
+  // whether ipv6 is supported.
+  optional bool supports_ipv6 = 7;
+
+  // If the router is a passpoint / hotspot 2.0 network
+  optional bool passpoint = 8;
+}
+
+message ConnectionEvent {
+
+  // Roam Type.
+  enum RoamType {
+
+    // Type is unknown.
+    ROAM_UNKNOWN = 0;
+
+    // No roaming.
+    ROAM_NONE  = 1;
+
+    // DBDC roaming.
+    ROAM_DBDC = 2;
+
+    // Enterprise roaming.
+    ROAM_ENTERPRISE = 3;
+
+    // User selected roaming.
+    ROAM_USER_SELECTED = 4;
+
+    // Unrelated.
+    ROAM_UNRELATED = 5;
+  }
+
+  // Connectivity Level Failure.
+  enum ConnectivityLevelFailure {
+
+    // Failure is unknown.
+    HLF_UNKNOWN = 0;
+
+    // No failure.
+    HLF_NONE = 1;
+
+    // DHCP failure.
+    HLF_DHCP = 2;
+
+    // No internet connection.
+    HLF_NO_INTERNET = 3;
+
+    // No internet connection.
+    HLF_UNWANTED = 4;
+  }
+
+  // Start time of the connection.
+  optional int64 start_time_millis = 1;// [(datapol.semantic_type) = ST_TIMESTAMP];
+
+  // Duration to connect.
+  optional int32 duration_taken_to_connect_millis = 2;
+
+  // Router information.
+  optional RouterFingerPrint router_fingerprint = 3;
+
+  // RSSI at the start of the connection.
+  optional int32 signal_strength = 4;
+
+  // Roam Type.
+  optional RoamType roam_type = 5;
+
+  // Result of the connection.
+  optional int32 connection_result = 6;
+
+  // Reasons for level 2 failure (needs to be coordinated with wpa-supplicant).
+  optional int32 level_2_failure_code = 7;
+
+  // Failures that happen at the connectivity layer.
+  optional ConnectivityLevelFailure connectivity_level_failure_code = 8;
+
+  // Has bug report been taken.
+  optional bool automatic_bug_report_taken = 9;
+}
+
+// Number of occurrences of a specific RSSI poll rssi value
+message RssiPollCount {
+  // RSSI
+  optional int32 rssi = 1;
+
+  // Number of RSSI polls with 'rssi'
+  optional int32 count = 2;
+}
+
+// Number of occurrences of a specific alert reason value
+message AlertReasonCount {
+  // Alert reason
+  optional int32 reason = 1;
+
+  // Number of alerts with |reason|.
+  optional int32 count = 2;
+}
+
+// Counts the number of instances of a specific Wifi Score calculated by WifiScoreReport
+message WifiScoreCount {
+  // Wifi Score
+  optional int32 score = 1;
+
+  // Number of Wifi score reports with this score
+  optional int32 count = 2;
+}
+
+// Number of occurrences of Soft AP session durations
+message SoftApDurationBucket {
+  // Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
+  // The (inclusive) lower bound of Soft AP session duration represented by this bucket
+  optional int32 duration_sec = 1;
+
+  // The size of this bucket
+  optional int32 bucket_size_sec = 2;
+
+  // Number of soft AP session durations that fit into this bucket
+  optional int32 count = 3;
+}
+
+// Number of occurrences of a soft AP session return code
+message SoftApReturnCodeCount {
+
+  enum SoftApStartResult {
+
+    // SoftApManager return code unknown
+    SOFT_AP_RETURN_CODE_UNKNOWN = 0;
+
+    // SoftAp started successfully
+    SOFT_AP_STARTED_SUCCESSFULLY = 1;
+
+    // Catch all for failures with no specific failure reason
+    SOFT_AP_FAILED_GENERAL_ERROR = 2;
+
+    // SoftAp failed to start due to NO_CHANNEL error
+    SOFT_AP_FAILED_NO_CHANNEL = 3;
+  }
+
+  // Historical, no longer used for writing as of 01/2017.
+  optional int32 return_code = 1 [deprecated = true];
+
+  // Occurences of this soft AP return code
+  optional int32 count = 2;
+
+  // Result of attempt to start SoftAp
+  optional SoftApStartResult start_result = 3;
+}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index bf3681b..447a47d 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -19,22 +19,17 @@
 
 LOCAL_STATIC_LIBRARIES :=
 
-rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
-
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
     frameworks/rs \
     frameworks/base/core/jni \
-    frameworks/base/libs/hwui \
-    $(rs_generated_include_dir)
+    frameworks/base/libs/hwui
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
 LOCAL_MODULE:= librs_jni
-LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
 LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS libRSDriver
+LOCAL_REQUIRED_MODULES := libRS
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index af370ff..2300da3 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -35,8 +35,8 @@
 #include "android_runtime/android_util_AssetManager.h"
 #include "android/graphics/GraphicsJNI.h"
 
-#include <rs.h>
 #include <rsEnv.h>
+#include <rsApiStubs.h>
 #include <gui/Surface.h>
 #include <gui/GLConsumer.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -1134,7 +1134,7 @@
     // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
     assert(dataSize == 5);
 
-    uintptr_t elementData[5];
+    uint32_t elementData[5];
     rsaElementGetNativeData((RsContext)con, (RsElement)id, elementData, dataSize);
 
     for(jint i = 0; i < dataSize; i ++) {
@@ -1157,7 +1157,7 @@
 
     uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
     const char **names = (const char **)malloc(dataSize * sizeof(const char *));
-    uint32_t *arraySizes = (uint32_t *)malloc(dataSize * sizeof(uint32_t));
+    size_t *arraySizes = (size_t *)malloc(dataSize * sizeof(size_t));
 
     rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
                              (uint32_t)dataSize);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3b3ce07..66576b5 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -166,7 +166,7 @@
         }
 
         public String toString() {
-            return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
+            return android.text.format.DateFormat.format("MM-dd HH:mm:ss ", mTimestamp) +
                     (mEnable ? "  Enabled " : " Disabled ") + " by " + mPackageName;
         }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index dfca02e..954a94e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -815,6 +815,8 @@
         intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+        mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
+                new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
 
         try {
             mNetd.registerObserver(mTethering);
@@ -3661,7 +3663,12 @@
         // Tear down existing lockdown if profile was removed
         mLockdownEnabled = LockdownVpnTracker.isEnabled();
         if (mLockdownEnabled) {
-            final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
+            byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+            if (profileTag == null) {
+                Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+                return false;
+            }
+            String profileName = new String(profileTag);
             final VpnProfile profile = VpnProfile.decode(
                     profileName, mKeyStore.get(Credentials.VPN + profileName));
             if (profile == null) {
@@ -4000,6 +4007,16 @@
         }
     };
 
+    private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Try creating lockdown tracker, since user present usually means
+            // unlocked keystore.
+            updateLockdownVpn();
+            mContext.unregisterReceiver(this);
+        }
+    };
+
     private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
             new HashMap<Messenger, NetworkFactoryInfo>();
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
@@ -4163,7 +4180,7 @@
         }
         ensureRequestableCapabilities(networkCapabilities);
 
-        if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
+        if (timeoutMs < 0) {
             throw new IllegalArgumentException("Bad timeout specified");
         }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62f4f19..82e6b42 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import android.Manifest;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
@@ -142,6 +141,10 @@
 
     private ServiceState[] mServiceState;
 
+    private int[] mVoiceActivationState;
+
+    private int[] mDataActivationState;
+
     private SignalStrength[] mSignalStrength;
 
     private boolean[] mMessageWaiting;
@@ -301,6 +304,8 @@
         mDataConnectionNetworkType = new int[numPhones];
         mCallIncomingNumber = new String[numPhones];
         mServiceState = new ServiceState[numPhones];
+        mVoiceActivationState = new int[numPhones];
+        mDataActivationState = new int[numPhones];
         mSignalStrength = new SignalStrength[numPhones];
         mMessageWaiting = new boolean[numPhones];
         mDataConnectionPossible = new boolean[numPhones];
@@ -315,6 +320,8 @@
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
             mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+            mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+            mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
             mCallIncomingNumber[i] =  "";
             mServiceState[i] =  new ServiceState();
             mSignalStrength[i] =  new SignalStrength();
@@ -644,6 +651,20 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) {
+                        try {
+                            r.callback.onVoiceActivationStateChanged(mVoiceActivationState[phoneId]);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
+                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) {
+                        try {
+                            r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -795,6 +816,67 @@
         broadcastServiceStateChanged(state, phoneId, subId);
     }
 
+    public void notifySimActivationStateChangedForPhoneId(int phoneId, int subId,
+            int activationType, int activationState) {
+        if (!checkNotifyPermission("notifySimActivationState()")){
+            return;
+        }
+        if (VDBG) {
+            log("notifySimActivationStateForPhoneId: subId=" + subId + " phoneId=" + phoneId
+                    + "type=" + activationType + " state=" + activationState);
+        }
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                switch (activationType) {
+                    case PhoneConstants.SIM_ACTIVATION_TYPE_VOICE:
+                        mVoiceActivationState[phoneId] = activationState;
+                        break;
+                    case PhoneConstants.SIM_ACTIVATION_TYPE_DATA:
+                        mDataActivationState[phoneId] = activationState;
+                        break;
+                    default:
+                        return;
+                }
+                for (Record r : mRecords) {
+                    if (VDBG) {
+                        log("notifySimActivationStateForPhoneId: r=" + r + " subId=" + subId
+                                + " phoneId=" + phoneId + "type=" + activationType
+                                + " state=" + activationState);
+                    }
+                    try {
+                        if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_VOICE) &&
+                                r.matchPhoneStateListenerEvent(
+                                        PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) &&
+                                idMatch(r.subId, subId, phoneId)) {
+                            if (DBG) {
+                                log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " state=" + activationState);
+                            }
+                            r.callback.onVoiceActivationStateChanged(activationState);
+                        }
+                        if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_DATA) &&
+                                r.matchPhoneStateListenerEvent(
+                                        PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) &&
+                                idMatch(r.subId, subId, phoneId)) {
+                            if (DBG) {
+                                log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
+                                        + " subId=" + subId + " phoneId=" + phoneId
+                                        + " state=" + activationState);
+                            }
+                            r.callback.onDataActivationStateChanged(activationState);
+                        }
+                    }  catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            } else {
+                log("notifySimActivationStateForPhoneId: INVALID phoneId=" + phoneId);
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     public void notifySignalStrengthForPhoneId(int phoneId, int subId,
                 SignalStrength signalStrength) {
         if (!checkNotifyPermission("notifySignalStrength()")) {
@@ -1324,6 +1406,8 @@
                 pw.println("  mCallState=" + mCallState[i]);
                 pw.println("  mCallIncomingNumber=" + mCallIncomingNumber[i]);
                 pw.println("  mServiceState=" + mServiceState[i]);
+                pw.println("  mVoiceActivationState= " + mVoiceActivationState[i]);
+                pw.println("  mDataActivationState= " + mDataActivationState[i]);
                 pw.println("  mSignalStrength=" + mSignalStrength[i]);
                 pw.println("  mMessageWaiting=" + mMessageWaiting[i]);
                 pw.println("  mCallForwarding=" + mCallForwarding[i]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 40617c8..1feaa72 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5357,7 +5357,8 @@
                     for (int pid : pids) {
                         if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
                         final long sime = SystemClock.elapsedRealtime();
-                        Debug.dumpNativeBacktraceToFile(pid, tracesPath);
+
+                        Debug.dumpNativeBacktraceToFileTimeout(pid, tracesPath, 10);
                         if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
                                 + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                     }
@@ -22277,4 +22278,29 @@
         // before the profile user is unlocked.
         return rInfo != null && rInfo.activityInfo != null;
     }
+
+    /**
+     * Attach an agent to the specified process (proces name or PID)
+     */
+    public void attachAgent(String process, String path) {
+        try {
+            synchronized (this) {
+                ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, "attachAgent");
+                if (proc == null || proc.thread == null) {
+                    throw new IllegalArgumentException("Unknown process: " + process);
+                }
+
+                boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+                if (!isDebuggable) {
+                    if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+                        throw new SecurityException("Process not debuggable: " + proc);
+                    }
+                }
+
+                proc.thread.attachAgent(path);
+            }
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Process disappeared");
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index adf6d36..2d0ccbd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -66,6 +66,8 @@
                     return runLenientBackgroundCheck(pw);
                 case "get-uid-state":
                     return getUidState(pw);
+                case "attach-agent":
+                    return runAttachAgent(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -183,6 +185,21 @@
         return 0;
     }
 
+    int runAttachAgent(PrintWriter pw) {
+        // TODO: revisit the permissions required for attaching agents
+        mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "attach-agent");
+        String process = getNextArgRequired();
+        String agent = getNextArgRequired();
+        String opt;
+        if ((opt = getNextArg()) != null) {
+            pw.println("Error: Unknown option: " + opt);
+            return -1;
+        }
+        mInternal.attachAgent(process, agent);
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -241,6 +258,8 @@
             pw.println("    Optionally controls lenient background check mode, returns current mode.");
             pw.println("  get-uid-state <UID>");
             pw.println("    Gets the process state of an app given its <UID>.");
+            pw.println("  attach-agent <PROCESS> <FILE>");
+            pw.println("    Attach an agent to the specified <PROCESS>, which may be either a process name or a PID.");
         }
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
deleted file mode 100644
index 1c9feb2..0000000
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * 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 com.android.server.connectivity;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.SystemService;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityMetricsEvent;
-import android.net.ConnectivityMetricsLogger;
-import android.net.IConnectivityMetricsLogger;
-import android.os.Binder;
-import android.os.Parcel;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-
-/** {@hide} */
-public class MetricsLoggerService extends SystemService {
-    private static String TAG = "ConnectivityMetricsLoggerService";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
-    public MetricsLoggerService(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void onStart() {
-        resetThrottlingCounters(System.currentTimeMillis());
-    }
-
-    @Override
-    public void onBootPhase(int phase) {
-        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
-            if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
-            publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
-                    mBinder);
-        }
-    }
-
-    // TODO: read these constants from system property
-    private final int EVENTS_NOTIFICATION_THRESHOLD                   = 300;
-    private final int MAX_NUMBER_OF_EVENTS                            = 1000;
-    private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
-    private final long THROTTLING_TIME_INTERVAL_MILLIS                = DateUtils.HOUR_IN_MILLIS;
-
-    private int mEventCounter = 0;
-
-    /**
-     * Reference of the last event in the list of cached events.
-     *
-     * When client of this service retrieves events by calling getEvents, it is passing
-     * ConnectivityMetricsEvent.Reference object. After getEvents returns, that object will
-     * contain this reference. The client can save it and use next time it calls getEvents.
-     * This way only new events will be returned.
-     */
-    private long mLastEventReference = 0;
-
-    private final int mThrottlingCounters[] =
-            new int[ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS];
-
-    private long mThrottlingIntervalBoundaryMillis;
-
-    private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
-
-    private void enforceConnectivityInternalPermission() {
-        getContext().enforceCallingOrSelfPermission(
-                android.Manifest.permission.CONNECTIVITY_INTERNAL,
-                "MetricsLoggerService");
-    }
-
-    private void enforceDumpPermission() {
-        getContext().enforceCallingOrSelfPermission(
-                android.Manifest.permission.DUMP,
-                "MetricsLoggerService");
-    }
-
-    private void resetThrottlingCounters(long currentTimeMillis) {
-        synchronized (mThrottlingCounters) {
-            for (int i = 0; i < mThrottlingCounters.length; i++) {
-                mThrottlingCounters[i] = 0;
-            }
-            mThrottlingIntervalBoundaryMillis =
-                    currentTimeMillis + THROTTLING_TIME_INTERVAL_MILLIS;
-        }
-    }
-
-    private void addEvent(ConnectivityMetricsEvent e) {
-        if (VDBG) {
-            Log.v(TAG, "writeEvent(" + e.toString() + ")");
-        }
-
-        while (mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
-            mEvents.removeFirst();
-        }
-
-        mEvents.addLast(e);
-    }
-
-    @VisibleForTesting
-    final MetricsLoggerImpl mBinder = new MetricsLoggerImpl();
-
-    /**
-     * Implementation of the IConnectivityMetricsLogger interface.
-     */
-    final class MetricsLoggerImpl extends IConnectivityMetricsLogger.Stub {
-
-        private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
-
-        @Override
-        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                    != PackageManager.PERMISSION_GRANTED) {
-                pw.println("Permission Denial: can't dump ConnectivityMetricsLoggerService " +
-                        "from from pid=" + Binder.getCallingPid() + ", uid=" +
-                        Binder.getCallingUid());
-                return;
-            }
-
-            boolean dumpSerializedSize = false;
-            boolean dumpEvents = false;
-            boolean dumpDebugInfo = false;
-            for (String arg : args) {
-                switch (arg) {
-                    case "--debug":
-                        dumpDebugInfo = true;
-                        break;
-
-                    case "--events":
-                        dumpEvents = true;
-                        break;
-
-                    case "--size":
-                        dumpSerializedSize = true;
-                        break;
-
-                    case "--all":
-                        dumpDebugInfo = true;
-                        dumpEvents = true;
-                        dumpSerializedSize = true;
-                        break;
-                }
-            }
-
-            synchronized (mEvents) {
-                pw.println("Number of events: " + mEvents.size());
-                pw.println("Counter: " + mEventCounter);
-                if (mEvents.size() > 0) {
-                    pw.println("Time span: " +
-                            DateUtils.formatElapsedTime(
-                                    (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
-                                            / 1000));
-                }
-
-                if (dumpSerializedSize) {
-                    Parcel p = Parcel.obtain();
-                    for (ConnectivityMetricsEvent e : mEvents) {
-                        p.writeParcelable(e, 0);
-                    }
-                    pw.println("Serialized data size: " + p.dataSize());
-                    p.recycle();
-                }
-
-                if (dumpEvents) {
-                    pw.println();
-                    pw.println("Events:");
-                    for (ConnectivityMetricsEvent e : mEvents) {
-                        pw.println(e.toString());
-                    }
-                }
-            }
-
-            if (dumpDebugInfo) {
-                synchronized (mThrottlingCounters) {
-                    pw.println();
-                    for (int i = 0; i < ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS; i++) {
-                        if (mThrottlingCounters[i] > 0) {
-                            pw.println("Throttling Counter #" + i + ": " + mThrottlingCounters[i]);
-                        }
-                    }
-                    pw.println("Throttling Time Remaining: " +
-                            DateUtils.formatElapsedTime(
-                                    (mThrottlingIntervalBoundaryMillis - System.currentTimeMillis())
-                                            / 1000));
-                }
-            }
-
-            synchronized (mPendingIntents) {
-                if (!mPendingIntents.isEmpty()) {
-                    pw.println();
-                    pw.println("Pending intents:");
-                    for (PendingIntent pi : mPendingIntents) {
-                        pw.println(pi.toString());
-                    }
-                }
-            }
-        }
-
-        public long logEvent(ConnectivityMetricsEvent event) {
-            ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
-            return logEvents(events);
-        }
-
-        /**
-         * @param events
-         *
-         * Note: All events must belong to the same component.
-         *
-         * @return 0 on success
-         *        <0 if error happened
-         *        >0 timestamp after which new events will be accepted
-         */
-        public long logEvents(ConnectivityMetricsEvent[] events) {
-            enforceConnectivityInternalPermission();
-
-            if (events == null || events.length == 0) {
-                Log.wtf(TAG, "No events passed to logEvents()");
-                return -1;
-            }
-
-            int componentTag = events[0].componentTag;
-            if (componentTag < 0 ||
-                    componentTag >= ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS) {
-                Log.wtf(TAG, "Unexpected tag: " + componentTag);
-                return -1;
-            }
-
-            synchronized (mThrottlingCounters) {
-                long currentTimeMillis = System.currentTimeMillis();
-                if (currentTimeMillis > mThrottlingIntervalBoundaryMillis) {
-                    resetThrottlingCounters(currentTimeMillis);
-                }
-
-                mThrottlingCounters[componentTag] += events.length;
-
-                if (mThrottlingCounters[componentTag] >
-                        THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT) {
-                    Log.w(TAG, "Too many events from #" + componentTag +
-                            ". Block until " + mThrottlingIntervalBoundaryMillis);
-
-                    return mThrottlingIntervalBoundaryMillis;
-                }
-            }
-
-            boolean sendPendingIntents = false;
-
-            synchronized (mEvents) {
-                for (ConnectivityMetricsEvent e : events) {
-                    if (e.componentTag != componentTag) {
-                        Log.wtf(TAG, "Unexpected tag: " + e.componentTag);
-                        return -1;
-                    }
-
-                    addEvent(e);
-                }
-
-                mLastEventReference += events.length;
-
-                mEventCounter += events.length;
-                if (mEventCounter >= EVENTS_NOTIFICATION_THRESHOLD) {
-                    mEventCounter = 0;
-                    sendPendingIntents = true;
-                }
-            }
-
-            if (sendPendingIntents) {
-                synchronized (mPendingIntents) {
-                    for (PendingIntent pi : mPendingIntents) {
-                        if (VDBG) Log.v(TAG, "Send pending intent");
-                        try {
-                            pi.send(getContext(), 0, null, null, null);
-                        } catch (PendingIntent.CanceledException e) {
-                            Log.e(TAG, "Pending intent canceled: " + pi);
-                            mPendingIntents.remove(pi);
-                        }
-                    }
-                }
-            }
-
-            return 0;
-        }
-
-        /**
-         * Retrieve events
-         *
-         * @param reference of the last event previously returned. The function will return
-         *                  events following it.
-         *                  If 0 then all events will be returned.
-         *                  After the function call it will contain reference of the
-         *                  last returned event.
-         * @return events
-         */
-        public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
-            enforceDumpPermission();
-            long ref = reference.getValue();
-            if (VDBG) Log.v(TAG, "getEvents(" + ref + ")");
-
-            ConnectivityMetricsEvent[] result;
-            synchronized (mEvents) {
-                if (ref > mLastEventReference) {
-                    Log.e(TAG, "Invalid reference");
-                    reference.setValue(mLastEventReference);
-                    return null;
-                }
-                if (ref < mLastEventReference - mEvents.size()) {
-                    ref = mLastEventReference - mEvents.size();
-                }
-
-                int numEventsToSkip =
-                        mEvents.size() // Total number of events
-                        - (int)(mLastEventReference - ref); // Number of events to return
-
-                result = new ConnectivityMetricsEvent[mEvents.size() - numEventsToSkip];
-                int i = 0;
-                for (ConnectivityMetricsEvent e : mEvents) {
-                    if (numEventsToSkip > 0) {
-                        numEventsToSkip--;
-                    } else {
-                        result[i++] = e;
-                    }
-                }
-
-                reference.setValue(mLastEventReference);
-            }
-
-            return result;
-        }
-
-        public boolean register(PendingIntent newEventsIntent) {
-            enforceDumpPermission();
-            if (VDBG) Log.v(TAG, "register(" + newEventsIntent + ")");
-
-            synchronized (mPendingIntents) {
-                if (mPendingIntents.remove(newEventsIntent)) {
-                    Log.w(TAG, "Replacing registered pending intent");
-                }
-                mPendingIntents.add(newEventsIntent);
-            }
-
-            return true;
-        }
-
-        public void unregister(PendingIntent newEventsIntent) {
-            enforceDumpPermission();
-            if (VDBG) Log.v(TAG, "unregister(" + newEventsIntent + ")");
-
-            synchronized (mPendingIntents) {
-                if (!mPendingIntents.remove(newEventsIntent)) {
-                    Log.e(TAG, "Pending intent is not registered");
-                }
-            }
-        }
-    };
-}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 9ffe2b7..c40780e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -809,19 +809,26 @@
             // portal.  If it is considered a captive portal, a different sign-in URL
             // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
             // proxy server.
-
-            // Consider 200 response with "Content-length=0" to not be a captive portal.
-            // There's no point in considering this a captive portal as the user cannot
-            // sign-in to an empty page.  Probably the result of a broken transparent proxy.
-            // See http://b/9972012.
-            if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) {
-                validationLog("Empty 200 response interpreted as 204 response.");
-                httpResponseCode = 204;
-            }
-
-            if (httpResponseCode == 200 && probeType == ValidationProbeEvent.PROBE_PAC) {
-                validationLog("PAC fetch 200 response interpreted as 204 response.");
-                httpResponseCode = 204;
+            if (httpResponseCode == 200) {
+                if (probeType == ValidationProbeEvent.PROBE_PAC) {
+                    validationLog("PAC fetch 200 response interpreted as 204 response.");
+                    httpResponseCode = 204;
+                } else if (urlConnection.getContentLengthLong() == 0) {
+                    // Consider 200 response with "Content-length=0" to not be a captive portal.
+                    // There's no point in considering this a captive portal as the user cannot
+                    // sign-in to an empty page. Probably the result of a broken transparent proxy.
+                    // See http://b/9972012.
+                    validationLog(
+                        "200 response with Content-length=0 interpreted as 204 response.");
+                    httpResponseCode = 204;
+                } else if (urlConnection.getContentLengthLong() == -1) {
+                    // When no Content-length (default value == -1), attempt to read a byte from the
+                    // response. Do not use available() as it is unreliable. See http://b/33498325.
+                    if (urlConnection.getInputStream().read() == -1) {
+                        validationLog("Empty 200 response interpreted as 204 response.");
+                        httpResponseCode = 204;
+                    }
+                }
             }
         } catch (IOException e) {
             validationLog("Probably not a portal: exception " + e);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 8e55ea5..1da5e69 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1010,10 +1010,9 @@
                 return false;
             }
 
-            protected boolean requestUpstreamMobileConnection() {
+            protected void requestUpstreamMobileConnection() {
                 mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
                 mUpstreamNetworkMonitor.registerMobileNetworkRequest();
-                return true;
             }
 
             protected void unrequestUpstreamMobileConnection() {
@@ -1060,9 +1059,13 @@
             }
 
             protected void chooseUpstreamType(boolean tryCell) {
+                final int upstreamType = findPreferredUpstreamType(tryCell);
+                setUpstreamByType(upstreamType);
+            }
+
+            protected int findPreferredUpstreamType(boolean tryCell) {
                 final ConnectivityManager cm = getConnectivityManager();
                 int upType = ConnectivityManager.TYPE_NONE;
-                String iface = null;
 
                 updateConfiguration(); // TODO - remove?
 
@@ -1102,7 +1105,8 @@
                         requestUpstreamMobileConnection();
                         break;
                     case ConnectivityManager.TYPE_NONE:
-                        if (tryCell && requestUpstreamMobileConnection()) {
+                        if (tryCell) {
+                            requestUpstreamMobileConnection();
                             // We think mobile should be coming up; don't set a retry.
                         } else {
                             sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
@@ -1119,7 +1123,13 @@
                         break;
                 }
 
+                return upType;
+            }
+
+            protected void setUpstreamByType(int upType) {
+                final ConnectivityManager cm = getConnectivityManager();
                 Network network = null;
+                String iface = null;
                 if (upType != ConnectivityManager.TYPE_NONE) {
                     LinkProperties linkProperties = cm.getLinkProperties(upType);
                     if (linkProperties != null) {
@@ -1361,9 +1371,9 @@
                 simChange.startListening();
                 mUpstreamNetworkMonitor.start();
 
-                mTryCell = true;  // better try something first pass or crazy tests cases will fail
-                chooseUpstreamType(mTryCell);
-                mTryCell = !mTryCell;
+                // Better try something first pass or crazy tests cases will fail.
+                chooseUpstreamType(true);
+                mTryCell = false;
             }
 
             @Override
@@ -1414,10 +1424,9 @@
                         break;
                     }
                     case CMD_UPSTREAM_CHANGED:
-                        // need to try DUN immediately if Wifi goes down
-                        mTryCell = true;
-                        chooseUpstreamType(mTryCell);
-                        mTryCell = !mTryCell;
+                        // Need to try DUN immediately if Wi-Fi goes down.
+                        chooseUpstreamType(true);
+                        mTryCell = false;
                         break;
                     case CMD_RETRY_UPSTREAM:
                         chooseUpstreamType(mTryCell);
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 e8a7ddb..710ab33 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -251,31 +251,33 @@
         }
 
         private void cleanupUpstream() {
-            if (mMyUpstreamIfaceName != null) {
-                // note that we don't care about errors here.
-                // sometimes interfaces are gone before we get
-                // to remove their rules, which generates errors.
-                // just do the best we can.
-                try {
-                    // about to tear down NAT; gather remaining statistics
-                    mStatsService.forceUpdate();
-                } catch (Exception e) {
-                    if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
-                }
-                try {
-                    mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
-                } catch (Exception e) {
-                    if (VDBG) Log.e(
-                            TAG, "Exception in removeInterfaceForward: " + e.toString());
-                }
-                try {
-                    mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
-                } catch (Exception e) {
-                    if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
-                }
-                mMyUpstreamIfaceName = null;
+            if (mMyUpstreamIfaceName == null) return;
+
+            cleanupUpstreamInterface(mMyUpstreamIfaceName);
+            mMyUpstreamIfaceName = null;
+        }
+
+        private void cleanupUpstreamInterface(String upstreamIface) {
+            // Note that we don't care about errors here.
+            // Sometimes interfaces are gone before we get
+            // to remove their rules, which generates errors.
+            // Just do the best we can.
+            try {
+                // About to tear down NAT; gather remaining statistics.
+                mStatsService.forceUpdate();
+            } catch (Exception e) {
+                if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
             }
-            return;
+            try {
+                mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
+            } catch (Exception e) {
+                if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
+            }
+            try {
+                mNMService.disableNat(mIfaceName, upstreamIface);
+            } catch (Exception e) {
+                if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
+            }
         }
 
         @Override
@@ -307,6 +309,7 @@
                                     newUpstreamIfaceName);
                         } catch (Exception e) {
                             Log.e(TAG, "Exception enabling Nat: " + e.toString());
+                            cleanupUpstreamInterface(newUpstreamIfaceName);
                             mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
                             transitionTo(mInitialState);
                             return true;
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 08a3332..6106093 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,8 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.LinkProperties;
@@ -66,12 +68,13 @@
     public static final int EVENT_ON_LINKPROPERTIES = 3;
     public static final int EVENT_ON_LOST           = 4;
 
-    private static final int LISTEN_ALL = 1;
-    private static final int TRACK_DEFAULT = 2;
-    private static final int MOBILE_REQUEST = 3;
+    private static final int CALLBACK_LISTEN_ALL = 1;
+    private static final int CALLBACK_TRACK_DEFAULT = 2;
+    private static final int CALLBACK_MOBILE_REQUEST = 3;
 
     private final Context mContext;
     private final StateMachine mTarget;
+    private final Handler mHandler;
     private final int mWhat;
     private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
     private ConnectivityManager mCM;
@@ -84,6 +87,7 @@
     public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
         mContext = ctx;
         mTarget = tgt;
+        mHandler = mTarget.getHandler();
         mWhat = what;
     }
 
@@ -98,11 +102,11 @@
 
         final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
                 .clearCapabilities().build();
-        mListenAllCallback = new UpstreamNetworkCallback(LISTEN_ALL);
-        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback);
+        mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
+        cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
 
-        mDefaultNetworkCallback = new UpstreamNetworkCallback(TRACK_DEFAULT);
-        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+        mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
+        cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
     }
 
     public void stop() {
@@ -136,30 +140,25 @@
             return;
         }
 
-        final NetworkRequest.Builder builder = new NetworkRequest.Builder()
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        if (mDunRequired) {
-            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                   .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
-        } else {
-            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        }
-        final NetworkRequest mobileUpstreamRequest = builder.build();
+        // The following use of the legacy type system cannot be removed until
+        // after upstream selection no longer finds networks by legacy type.
+        // See also http://b/34364553 .
+        final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
+
+        final NetworkRequest mobileUpstreamRequest = new NetworkRequest.Builder()
+                .setCapabilities(ConnectivityManager.networkCapabilitiesForType(legacyType))
+                .build();
 
         // The existing default network and DUN callbacks will be notified.
         // Therefore, to avoid duplicate notifications, we only register a no-op.
-        mMobileNetworkCallback = new UpstreamNetworkCallback(MOBILE_REQUEST);
+        mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
 
         // TODO: Change the timeout from 0 (no onUnavailable callback) to some
         // moderate callback timeout. This might be useful for updating some UI.
         // Additionally, we log a message to aid in any subsequent debugging.
         Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
 
-        // The following use of the legacy type system cannot be removed until
-        // after upstream selection no longer finds networks by legacy type.
-        // See also b/34364553.
-        final int apnType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
-        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, apnType);
+        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
     }
 
     public void releaseMobileNetworkRequest() {
@@ -184,17 +183,42 @@
         // Always request whatever extra information we can, in case this
         // was already up when start() was called, in which case we would
         // not have been notified of any information that had not changed.
-        final NetworkCallback cb =
-                (callbackType == TRACK_DEFAULT) ? mDefaultNetworkCallback :
-                (callbackType == MOBILE_REQUEST) ? mMobileNetworkCallback : null;
-        if (cb != null) {
-            final ConnectivityManager cm = cm();
-            cm.requestNetworkCapabilities(mDefaultNetworkCallback);
-            cm.requestLinkProperties(mDefaultNetworkCallback);
-        }
+        switch (callbackType) {
+            case CALLBACK_LISTEN_ALL:
+                break;
+            case CALLBACK_TRACK_DEFAULT:
+                if (mDefaultNetworkCallback == null) {
+                    // The callback was unregistered in the interval between
+                    // ConnectivityService enqueueing onAvailable() and our
+                    // handling of it here on the mHandler thread.
+                    //
+                    // Clean-up of this network entry is deferred to the
+                    // handling of onLost() by other callbacks.
+                    //
+                    // These request*() calls can be deleted post oag/339444.
+                    return;
+                }
 
-        if (callbackType == TRACK_DEFAULT) {
-            mCurrentDefault = network;
+                cm().requestNetworkCapabilities(mDefaultNetworkCallback);
+                cm().requestLinkProperties(mDefaultNetworkCallback);
+                mCurrentDefault = network;
+                break;
+            case CALLBACK_MOBILE_REQUEST:
+                if (mMobileNetworkCallback == null) {
+                    // The callback was unregistered in the interval between
+                    // ConnectivityService enqueueing onAvailable() and our
+                    // handling of it here on the mHandler thread.
+                    //
+                    // Clean-up of this network entry is deferred to the
+                    // handling of onLost() by other callbacks.
+                    //
+                    // These request*() calls can be deleted post oag/339444.
+                    return;
+                }
+
+                cm().requestNetworkCapabilities(mMobileNetworkCallback);
+                cm().requestLinkProperties(mMobileNetworkCallback);
+                break;
         }
 
         // Requesting updates for mListenAllCallback is not currently possible
@@ -262,7 +286,7 @@
     }
 
     private void handleLost(int callbackType, Network network) {
-        if (callbackType == TRACK_DEFAULT) {
+        if (callbackType == CALLBACK_TRACK_DEFAULT) {
             mCurrentDefault = null;
             // Receiving onLost() for a default network does not necessarily
             // mean the network is gone.  We wait for a separate notification
@@ -296,8 +320,9 @@
     }
 
     /**
-     * A NetworkCallback class that relays information of interest to the
-     * tethering master state machine thread for subsequent processing.
+     * A NetworkCallback class that handles information of interest directly
+     * in the thread on which it is invoked. To avoid locking, this MUST be
+     * run on the same thread as the target state machine's handler.
      */
     private class UpstreamNetworkCallback extends NetworkCallback {
         private final int mCallbackType;
@@ -308,22 +333,35 @@
 
         @Override
         public void onAvailable(Network network) {
-            mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network));
+            checkExpectedThread();
+            handleAvailable(mCallbackType, network);
         }
 
         @Override
         public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
-            mTarget.getHandler().post(() -> handleNetCap(network, newNc));
+            checkExpectedThread();
+            handleNetCap(network, newNc);
         }
 
         @Override
         public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
-            mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
+            checkExpectedThread();
+            handleLinkProp(network, newLp);
         }
 
+        // TODO: Handle onNetworkSuspended();
+        // TODO: Handle onNetworkResumed();
+
         @Override
         public void onLost(Network network) {
-            mTarget.getHandler().post(() -> handleLost(mCallbackType, network));
+            checkExpectedThread();
+            handleLost(mCallbackType, network);
+        }
+
+        private void checkExpectedThread() {
+            if (Looper.myLooper() != mHandler.getLooper()) {
+                Log.wtf(TAG, "Handling callback in unexpected thread.");
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 55917fc..0c7e44e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -24,7 +24,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Predicate;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
@@ -34,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.function.Predicate;
 
 /**
  * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -72,7 +72,7 @@
     // Predicate for whether the given logical address is remote device's one or not.
     private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
         @Override
-        public boolean apply(Integer address) {
+        public boolean test(Integer address) {
             return !isAllocatedLocalDeviceAddress(address);
         }
     };
@@ -80,7 +80,7 @@
     // Predicate whether the given logical address is system audio's one or not
     private final Predicate<Integer> mSystemAudioAddressPredicate = new Predicate<Integer>() {
         @Override
-        public boolean apply(Integer address) {
+        public boolean test(Integer address) {
             return HdmiUtils.getTypeFromAddress(address) == Constants.ADDR_AUDIO_SYSTEM;
         }
     };
@@ -403,7 +403,7 @@
         switch (iterationStrategy) {
             case Constants.POLL_ITERATION_IN_ORDER:
                 for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) {
-                    if (pickPredicate.apply(i)) {
+                    if (pickPredicate.test(i)) {
                         pollingCandidates.add(i);
                     }
                 }
@@ -411,7 +411,7 @@
             case Constants.POLL_ITERATION_REVERSE_ORDER:
             default:  // The default is reverse order.
                 for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) {
-                    if (pickPredicate.apply(i)) {
+                    if (pickPredicate.test(i)) {
                         pollingCandidates.add(i);
                     }
                 }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ae98077..e2e834d 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -477,12 +477,6 @@
         public void onLost(Network network) {
             releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
         }
-
-        @Override
-        public void onUnavailable() {
-            // timeout, it was not possible to establish the required connection
-            releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
-        }
     };
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -902,8 +896,7 @@
         NetworkRequest request = requestBuilder.build();
         mConnMgr.requestNetwork(
                 request,
-                mSuplConnectivityCallback,
-                ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
+                mSuplConnectivityCallback);
     }
 
     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d31c7b5..22c5e85 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2078,12 +2078,14 @@
                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
                 return null;
             }
-            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            try {
-                writePolicyXml(baos, true /*forBackup*/);
-                return baos.toByteArray();
-            } catch (IOException e) {
-                Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+            synchronized(mPolicyFile) {
+                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                try {
+                    writePolicyXml(baos, true /*forBackup*/);
+                    return baos.toByteArray();
+                } catch (IOException e) {
+                    Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+                }
             }
             return null;
         }
@@ -2101,12 +2103,14 @@
                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
                 return;
             }
-            final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
-            try {
-                readPolicyXml(bais, true /*forRestore*/);
-                savePolicyFile();
-            } catch (NumberFormatException | XmlPullParserException | IOException e) {
-                Slog.w(TAG, "applyRestore: error reading payload", e);
+            synchronized(mPolicyFile) {
+                final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+                try {
+                    readPolicyXml(bais, true /*forRestore*/);
+                    savePolicyFile();
+                } catch (NumberFormatException | XmlPullParserException | IOException e) {
+                    Slog.w(TAG, "applyRestore: error reading payload", e);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 0fe1539..522c2e8 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -69,6 +69,9 @@
     // Append autoplay to existing seinfo label
     private static final String AUTOPLAY_APP_STR = ":autoplayapp";
 
+    // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
+    private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
+
     /**
      * Load the mac_permissions.xml file containing all seinfo assignments used to
      * label apps. The loaded mac_permissions.xml file is determined by the
@@ -290,6 +293,8 @@
         if (pkg.applicationInfo.isPrivilegedApp())
             pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
 
+        pkg.applicationInfo.seinfo += TARGETSDKVERSION_STR + pkg.applicationInfo.targetSdkVersion;
+
         if (DEBUG_POLICY_INSTALL) {
             Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
                     "seinfo=" + pkg.applicationInfo.seinfo);
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index b704eb1..3c73c88 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -20,7 +20,7 @@
 
 import java.io.File;
 import java.io.IOException;
-import libcore.tzdata.update2.TimeZoneBundleInstaller;
+import libcore.tzdata.update2.TimeZoneDistroInstaller;
 
 /**
  * An install receiver responsible for installing timezone data updates.
@@ -34,14 +34,14 @@
     private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
     private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
     private static final String UPDATE_VERSION_FILE_NAME = "version";
-    private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_bundle.zip";
+    private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_distro.zip";
 
-    private final TimeZoneBundleInstaller installer;
+    private final TimeZoneDistroInstaller installer;
 
     public TzDataInstallReceiver() {
         super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
                 UPDATE_VERSION_FILE_NAME);
-        installer = new TimeZoneBundleInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
+        installer = new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 27d95a4..de4a55b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -61,7 +61,6 @@
 import com.android.server.camera.CameraService;
 import com.android.server.clipboard.ClipboardService;
 import com.android.server.connectivity.IpConnectivityMetrics;
-import com.android.server.connectivity.MetricsLoggerService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.display.NightDisplayService;
@@ -662,10 +661,6 @@
                 mSystemServiceManager.startService(BluetoothService.class);
             }
 
-            traceBeginAndSlog("ConnectivityMetricsLoggerService");
-            mSystemServiceManager.startService(MetricsLoggerService.class);
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
             traceBeginAndSlog("IpConnectivityMetrics");
             mSystemServiceManager.startService(IpConnectivityMetrics.class);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 00c36f9..99eb3d2 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -32,6 +32,7 @@
 import android.hardware.usb.UsbManager;
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
+import android.os.BatteryManager;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -111,6 +112,7 @@
     private static final int MSG_USER_SWITCHED = 5;
     private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
     private static final int MSG_UPDATE_HOST_STATE = 7;
+    private static final int MSG_UPDATE_CHARGING_STATE = 9;
 
     private static final int AUDIO_MODE_SOURCE = 1;
 
@@ -192,6 +194,15 @@
         }
     };
 
+    private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+             int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+             boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+             mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
+        }
+    };
+
     public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
         mContext = context;
         mUsbAlsaManager = alsaManager;
@@ -216,6 +227,8 @@
         }
         mContext.registerReceiver(mHostReceiver,
                 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
+        mContext.registerReceiver(mChargingReceiver,
+                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
     }
 
     private UsbSettingsManager getCurrentSettings() {
@@ -330,6 +343,7 @@
         private int mUsbNotificationId;
         private boolean mAdbNotificationShown;
         private int mCurrentUser = UserHandle.USER_NULL;
+        private boolean mUsbCharging;
 
         public UsbHandler(Looper looper) {
             super(looper);
@@ -428,7 +442,10 @@
             args.argi2 = sourcePower ? 1 :0;
             args.argi3 = sinkPower ? 1 :0;
 
-            obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget();
+            removeMessages(MSG_UPDATE_HOST_STATE);
+            Message msg = obtainMessage(MSG_UPDATE_HOST_STATE, args);
+            // debounce rapid transitions of connect/disconnect on type-c ports
+            sendMessageDelayed(msg, UPDATE_DELAY);
         }
 
         private boolean waitForState(String state) {
@@ -766,6 +783,10 @@
                         mPendingBootBroadcast = true;
                     }
                     break;
+                case MSG_UPDATE_CHARGING_STATE:
+                    mUsbCharging = (msg.arg1 == 1);
+                    updateUsbNotification();
+                    break;
                 case MSG_ENABLE_ADB:
                     setAdbEnabled(msg.arg1 == 1);
                     break;
@@ -850,7 +871,7 @@
                 }
             } else if (mSourcePower) {
                 id = com.android.internal.R.string.usb_supplying_notification_title;
-            } else if (mHostConnected && mSinkPower) {
+            } else if (mHostConnected && mSinkPower && mUsbCharging) {
                 id = com.android.internal.R.string.usb_charging_notification_title;
             }
             if (id != mUsbNotificationId) {
@@ -954,6 +975,7 @@
             pw.println("  mHostConnected: " + mHostConnected);
             pw.println("  mSourcePower: " + mSourcePower);
             pw.println("  mSinkPower: " + mSinkPower);
+            pw.println("  mUsbCharging: " + mUsbCharging);
             try {
                 pw.println("  Kernel state: "
                         + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 58c5002..1507082 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -16,12 +16,21 @@
 
 package android.telecom;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.ParcelFileDescriptor;
 
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
 import java.lang.String;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -828,6 +837,143 @@
          * @param extras Extras associated with the connection event.
          */
         public void onConnectionEvent(Call call, String event, Bundle extras) {}
+
+        /**
+         * Invoked when the RTT mode changes for this call.
+         * @param call The call whose RTT mode has changed.
+         * @param mode the new RTT mode, one of
+         * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
+         *             or {@link RttCall#RTT_MODE_VCO}
+         */
+        public void onRttModeChanged(Call call, int mode) {}
+
+        /**
+         * Invoked when the call's RTT status changes, either from off to on or from on to off.
+         * @param call The call whose RTT status has changed.
+         * @param enabled whether RTT is now enabled or disabled
+         * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
+         *                on, null otherwise.
+         */
+        public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
+
+        /**
+         * Invoked when the remote end of the connection has requested that an RTT communication
+         * channel be opened. A response to this should be sent via {@link #respondToRttRequest}
+         * with the same ID that this method is invoked with.
+         * @param call The call which the RTT request was placed on
+         * @param id The ID of the request.
+         */
+        public void onRttRequest(Call call, int id) {}
+    }
+
+    /**
+     * A class that holds the state that describes the state of the RTT channel to the remote
+     * party, if it is active.
+     */
+    public static final class RttCall {
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
+        public @interface RttAudioMode {}
+
+        /**
+         * For metrics use. Default value in the proto.
+         * @hide
+         */
+        public static final int RTT_MODE_INVALID = 0;
+
+        /**
+         * Indicates that there should be a bidirectional audio stream between the two parties
+         * on the call.
+         */
+        public static final int RTT_MODE_FULL = 1;
+
+        /**
+         * Indicates that the local user should be able to hear the audio stream from the remote
+         * user, but not vice versa. Equivalent to muting the microphone.
+         */
+        public static final int RTT_MODE_HCO = 2;
+
+        /**
+         * Indicates that the remote user should be able to hear the audio stream from the local
+         * user, but not vice versa. Equivalent to setting the volume to zero.
+         */
+        public static final int RTT_MODE_VCO = 3;
+
+        private static final int READ_BUFFER_SIZE = 1000;
+
+        private InputStreamReader mReceiveStream;
+        private OutputStreamWriter mTransmitStream;
+        private int mRttMode;
+        private final InCallAdapter mInCallAdapter;
+        private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
+
+        /**
+         * @hide
+         */
+        public RttCall(InputStreamReader receiveStream, OutputStreamWriter transmitStream,
+                int mode, InCallAdapter inCallAdapter) {
+            mReceiveStream = receiveStream;
+            mTransmitStream = transmitStream;
+            mRttMode = mode;
+            mInCallAdapter = inCallAdapter;
+        }
+
+        /**
+         * Returns the current RTT audio mode.
+         * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
+         * {@link #RTT_MODE_HCO}.
+         */
+        public int getRttAudioMode() {
+            return mRttMode;
+        }
+
+        /**
+         * Sets the RTT audio mode. The requested mode change will be communicated through
+         * {@link Callback#onRttModeChanged(Call, int)}.
+         * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
+         * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
+         */
+        public void setRttMode(@RttAudioMode int mode) {
+            mInCallAdapter.setRttMode(mode);
+        }
+
+        /**
+         * Writes the string {@param input} into the outgoing text stream for this RTT call. Since
+         * RTT transmits text in real-time, this method should be called once for each character
+         * the user enters into the device.
+         *
+         * This method is not thread-safe -- calling it from multiple threads simultaneously may
+         * lead to interleaved text.
+         * @param input The message to send to the remote user.
+         */
+        public void write(String input) throws IOException {
+            mTransmitStream.write(input);
+            mTransmitStream.flush();
+        }
+
+        /**
+         * Reads a string from the remote user, blocking if there is no data available. Returns
+         * {@code null} if the RTT conversation has been terminated and there is no further data
+         * to read.
+         *
+         * This method is not thread-safe -- calling it from multiple threads simultaneously may
+         * lead to interleaved text.
+         * @return A string containing text sent by the remote user, or {@code null} if the
+         * conversation has been terminated or if there was an error while reading.
+         */
+        public String read() {
+            try {
+                int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+                if (numRead < 0) {
+                    return null;
+                }
+                return new String(mReadBuffer, 0, numRead);
+            } catch (IOException e) {
+                Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
+                return null;
+            }
+        }
     }
 
     /**
@@ -853,8 +999,10 @@
     private String mParentId = null;
     private int mState;
     private List<String> mCannedTextResponses = null;
+    private String mCallingPackage;
     private String mRemainingPostDialSequence;
     private VideoCallImpl mVideoCallImpl;
+    private RttCall mRttCall;
     private Details mDetails;
     private Bundle mExtras;
 
@@ -1053,6 +1201,34 @@
     }
 
     /**
+     * Sends an RTT upgrade request to the remote end of the connection. Success is not
+     * guaranteed, and notification of success will be via the
+     * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
+     */
+    public void sendRttRequest() {
+        mInCallAdapter.sendRttRequest();
+    }
+
+    /**
+     * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
+     * callback.
+     * The ID used here should be the same as the ID that was received via the callback.
+     * @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
+     * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
+     */
+    public void respondToRttRequest(int id, boolean accept) {
+        mInCallAdapter.respondToRttRequest(id, accept);
+    }
+
+    /**
+     * Terminate the RTT session on this call. The resulting state change will be notified via
+     * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
+     */
+    public void stopRtt() {
+        mInCallAdapter.stopRtt();
+    }
+
+    /**
      * Adds some extras to this {@link Call}.  Existing keys are replaced and new ones are
      * added.
      * <p>
@@ -1232,6 +1408,23 @@
     }
 
     /**
+     * Returns this call's RttCall object. The {@link RttCall} instance is used to send and
+     * receive RTT text data, as well as to change the RTT mode.
+     * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
+     */
+    public @Nullable RttCall getRttCall() {
+        return mRttCall;
+    }
+
+    /**
+     * Returns whether this call has an active RTT connection.
+     * @return true if there is a connection, false otherwise.
+     */
+    public boolean isRttActive() {
+        return mRttCall != null;
+    }
+
+    /**
      * Registers a callback to this {@code Call}.
      *
      * @param callback A {@code Callback}.
@@ -1340,19 +1533,22 @@
     }
 
     /** {@hide} */
-    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
+    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage) {
         mPhone = phone;
         mTelecomCallId = telecomCallId;
         mInCallAdapter = inCallAdapter;
         mState = STATE_NEW;
+        mCallingPackage = callingPackage;
     }
 
     /** {@hide} */
-    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
+    Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
+            String callingPackage) {
         mPhone = phone;
         mTelecomCallId = telecomCallId;
         mInCallAdapter = inCallAdapter;
         mState = state;
+        mCallingPackage = callingPackage;
     }
 
     /** {@hide} */
@@ -1362,6 +1558,7 @@
 
     /** {@hide} */
     final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
+
         // First, we update the internal state as far as possible before firing any updates.
         Details details = Details.createFromParcelableCall(parcelableCall);
         boolean detailsChanged = !Objects.equals(mDetails, details);
@@ -1377,7 +1574,7 @@
             cannedTextResponsesChanged = true;
         }
 
-        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
+        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage);
         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
                 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
         if (videoCallChanged) {
@@ -1421,6 +1618,32 @@
             fireConferenceableCallsChanged();
         }
 
+        boolean isRttChanged = false;
+        boolean rttModeChanged = false;
+        if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+            ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
+            InputStreamReader receiveStream = new InputStreamReader(
+                    new ParcelFileDescriptor.AutoCloseInputStream(
+                            parcelableRttCall.getReceiveStream()),
+                    StandardCharsets.UTF_8);
+            OutputStreamWriter transmitStream = new OutputStreamWriter(
+                    new ParcelFileDescriptor.AutoCloseOutputStream(
+                            parcelableRttCall.getTransmitStream()),
+                    StandardCharsets.UTF_8);
+            RttCall newRttCall = new Call.RttCall(
+                    receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
+            if (mRttCall == null) {
+                isRttChanged = true;
+            } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
+                rttModeChanged = true;
+            }
+            mRttCall = newRttCall;
+        } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
+                && parcelableCall.getIsRttCallChanged()) {
+            isRttChanged = true;
+            mRttCall = null;
+        }
+
         // Now we fire updates, ensuring that any client who listens to any of these notifications
         // gets the most up-to-date state.
 
@@ -1442,6 +1665,12 @@
         if (childrenChanged) {
             fireChildrenChanged(getChildren());
         }
+        if (isRttChanged) {
+            fireOnIsRttChanged(mRttCall != null, mRttCall);
+        }
+        if (rttModeChanged) {
+            fireOnRttModeChanged(mRttCall.getRttAudioMode());
+        }
 
         // If we have transitioned to DISCONNECTED, that means we need to notify clients and
         // remove ourselves from the Phone. Note that we do this after completing all state updates
@@ -1472,6 +1701,15 @@
         fireOnConnectionEvent(event, extras);
     }
 
+    /** {@hide} */
+    final void internalOnRttUpgradeRequest(final int requestId) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(() -> callback.onRttRequest(call, requestId));
+        }
+    }
+
     private void fireStateChanged(final int newState) {
         for (CallbackRecord<Callback> record : mCallbackRecords) {
             final Call call = this;
@@ -1640,6 +1878,32 @@
     }
 
     /**
+     * Notifies listeners of an RTT on/off change
+     *
+     * @param enabled True if RTT is now enabled, false otherwise
+     */
+    private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
+        }
+    }
+
+    /**
+     * Notifies listeners of a RTT mode change
+     *
+     * @param mode The new RTT mode
+     */
+    private void fireOnRttModeChanged(final int mode) {
+        for (CallbackRecord<Callback> record : mCallbackRecords) {
+            final Call call = this;
+            final Callback callback = record.getCallback();
+            record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
+        }
+    }
+
+    /**
      * Determines if two bundles are equal.
      *
      * @param bundle The original bundle.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 560b616..3e690b9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,15 +25,20 @@
 import android.annotation.SystemApi;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.ArraySet;
 import android.view.Surface;
 
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -384,8 +389,14 @@
      */
     public static final int PROPERTY_SELF_MANAGED = 1<<7;
 
+    /**
+     * When set, indicates that a connection has an active RTT session associated with it.
+     * @hide
+     */
+    public static final int PROPERTY_IS_RTT = 1 << 8;
+
     //**********************************************************************************************
-    // Next PROPERTY value: 1<<8
+    // Next PROPERTY value: 1<<9
     //**********************************************************************************************
 
     /**
@@ -428,6 +439,31 @@
             "android.telecom.extra.DISABLE_ADD_CALL";
 
     /**
+     * String connection extra key on a {@link Connection} or {@link Conference} which contains the
+     * original Connection ID associated with the connection.  Used in
+     * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a
+     * connection/conference added via
+     * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and
+     * {@link ConnectionService#addConference(Conference)} APIs.  This is important to pass to
+     * Telecom for when it deals with RemoteConnections.  When the ConnectionManager wraps the
+     * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to
+     * be a way to ensure that we don't add the connection again as a duplicate.
+     * <p>
+     * For example, the TelephonyCS calls addExistingConnection for a Connection with ID
+     * {@code TelephonyCS@1}.  The ConnectionManager learns of this via
+     * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this
+     * in a new {@link Connection} which it adds to Telecom via
+     * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}.  As part of
+     * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}).
+     * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
+     * ID it originally referred to the connection as.  Thus Telecom needs to know that the
+     * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
+     * @hide
+     */
+    public static final String EXTRA_ORIGINAL_CONNECTION_ID =
+            "android.telecom.extra.ORIGINAL_CONNECTION_ID";
+
+    /**
      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
      * {@link #sendConnectionEvent(String, Bundle)}.
@@ -731,6 +767,65 @@
     }
 
     /**
+     * Provides methods to read and write RTT data to/from the in-call app.
+     * @hide
+     */
+    public static final class RttTextStream {
+        private static final int READ_BUFFER_SIZE = 1000;
+        private final InputStreamReader mPipeFromInCall;
+        private final OutputStreamWriter mPipeToInCall;
+        private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
+
+        /**
+         * @hide
+         */
+        public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
+            mPipeFromInCall = new InputStreamReader(
+                    new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+            mPipeToInCall = new OutputStreamWriter(
+                    new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+        }
+
+        /**
+         * Writes the string {@param input} into the text stream to the UI for this RTT call. Since
+         * RTT transmits text in real-time, this method should be called as often as text snippets
+         * are received from the remote user, even if it is only one character.
+         *
+         * This method is not thread-safe -- calling it from multiple threads simultaneously may
+         * lead to interleaved text.
+         * @param input The message to send to the in-call app.
+         */
+        public void write(String input) throws IOException {
+            mPipeToInCall.write(input);
+            mPipeToInCall.flush();
+        }
+
+
+        /**
+         * Reads a string from the in-call app, blocking if there is no data available. Returns
+         * {@code null} if the RTT conversation has been terminated and there is no further data
+         * to read.
+         *
+         * This method is not thread-safe -- calling it from multiple threads simultaneously may
+         * lead to interleaved text.
+         * @return A string containing text entered by the user, or {@code null} if the
+         * conversation has been terminated or if there was an error while reading.
+         */
+        public String read() {
+            try {
+                int numRead = mPipeFromInCall.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+                if (numRead < 0) {
+                    return null;
+                }
+                return new String(mReadBuffer, 0, numRead);
+            } catch (IOException e) {
+                Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
+                return null;
+            }
+        }
+    }
+
+    /**
      * Provides a means of controlling the video session associated with a {@link Connection}.
      * <p>
      * Implementations create a custom subclass of {@link VideoProvider} and the
@@ -774,7 +869,7 @@
         public static final int SESSION_EVENT_TX_STOP = 4;
 
         /**
-         * A camera failure has occurred for the selected camera.  The {@link InCallService} can use
+         * A camera failure has occurred for the selected camera.  The {@link VideoProvider} can use
          * this as a cue to inform the user the camera is not available.
          * @see #handleCallSessionEvent(int)
          */
@@ -782,13 +877,21 @@
 
         /**
          * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
-         * for operation.  The {@link InCallService} can use this as a cue to inform the user that
+         * for operation.  The {@link VideoProvider} can use this as a cue to inform the user that
          * the camera has become available again.
          * @see #handleCallSessionEvent(int)
          */
         public static final int SESSION_EVENT_CAMERA_READY = 6;
 
         /**
+         * Session event raised by Telecom when
+         * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the
+         * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission.
+         * @see #handleCallSessionEvent(int)
+         */
+        public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7;
+
+        /**
          * Session modify request was successful.
          * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
          */
@@ -837,6 +940,8 @@
         private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
         private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
         private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
+        private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR =
+                "CAMERA_PERMISSION_ERROR";
         private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
 
         private VideoProvider.VideoProviderHandler mMessageHandler;
@@ -895,8 +1000,17 @@
                         break;
                     }
                     case MSG_SET_CAMERA:
-                        onSetCamera((String) msg.obj);
-                        break;
+                    {
+                        SomeArgs args = (SomeArgs) msg.obj;
+                        try {
+                            onSetCamera((String) args.arg1);
+                            onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
+                                    args.argi2);
+                        } finally {
+                            args.recycle();
+                        }
+                    }
+                    break;
                     case MSG_SET_PREVIEW_SURFACE:
                         onSetPreviewSurface((Surface) msg.obj);
                         break;
@@ -951,8 +1065,19 @@
                         MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
             }
 
-            public void setCamera(String cameraId) {
-                mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
+            public void setCamera(String cameraId, String callingPackageName) {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = cameraId;
+                // Propagate the calling package; originally determined in
+                // android.telecom.InCallService.VideoCall#setCamera(String) from the calling
+                // process.
+                args.arg2 = callingPackageName;
+                // Pass along the uid and pid of the calling app; this gets lost when we put the
+                // message onto the handler.  These are required for Telecom to perform a permission
+                // check to see if the calling app is able to use the camera.
+                args.argi1 = Binder.getCallingUid();
+                args.argi2 = Binder.getCallingPid();
+                mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
             }
 
             public void setPreviewSurface(Surface surface) {
@@ -1037,6 +1162,29 @@
         public abstract void onSetCamera(String cameraId);
 
         /**
+         * Sets the camera to be used for the outgoing video.
+         * <p>
+         * The {@link VideoProvider} should respond by communicating the capabilities of the chosen
+         * camera via
+         * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
+         * <p>
+         * This prototype is used internally to ensure that the calling package name, UID and PID
+         * are sent to Telecom so that can perform a camera permission check on the caller.
+         * <p>
+         * Sent from the {@link InCallService} via
+         * {@link InCallService.VideoCall#setCamera(String)}.
+         *
+         * @param cameraId The id of the camera (use ids as reported by
+         * {@link CameraManager#getCameraIdList()}).
+         * @param callingPackageName The AppOpps package name of the caller.
+         * @param callingUid The UID of the caller.
+         * @param callingPid The PID of the caller.
+         * @hide
+         */
+        public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
+                int callingPid) {}
+
+        /**
          * Sets the surface to be used for displaying a preview of what the user's camera is
          * currently capturing.  When video transmission is enabled, this is the video signal which
          * is sent to the remote device.
@@ -1222,7 +1370,8 @@
          *      {@link VideoProvider#SESSION_EVENT_TX_START},
          *      {@link VideoProvider#SESSION_EVENT_TX_STOP},
          *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
-         *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
+         *      {@link VideoProvider#SESSION_EVENT_CAMERA_READY},
+         *      {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}.
          */
         public void handleCallSessionEvent(int event) {
             if (mVideoCallbacks != null) {
@@ -1371,6 +1520,8 @@
                     return SESSION_EVENT_TX_START_STR;
                 case SESSION_EVENT_TX_STOP:
                     return SESSION_EVENT_TX_STOP_STR;
+                case SESSION_EVENT_CAMERA_PERMISSION_ERROR:
+                    return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR;
                 default:
                     return SESSION_EVENT_UNKNOWN_STR + " " + event;
             }
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 2343462..054de4c 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -19,6 +19,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 
 /**
@@ -27,13 +28,121 @@
  */
 public final class ConnectionRequest implements Parcelable {
 
-    // TODO: Token to limit recursive invocations
+    /**
+     * Builder class for {@link ConnectionRequest}
+     * @hide
+     */
+    public static final class Builder {
+        private PhoneAccountHandle mAccountHandle;
+        private Uri mAddress;
+        private Bundle mExtras;
+        private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+        private String mTelecomCallId;
+        private boolean mShouldShowIncomingCallUi = false;
+        private ParcelFileDescriptor mRttPipeToInCall;
+        private ParcelFileDescriptor mRttPipeFromInCall;
+
+        public Builder() { }
+
+        /**
+         * Sets the phone account handle for the resulting {@link ConnectionRequest}
+         * @param accountHandle The accountHandle which should be used to place the call.
+         */
+        public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+            this.mAccountHandle = accountHandle;
+            return this;
+        }
+
+        /**
+         * Sets the address for the resulting {@link ConnectionRequest}
+         * @param address The address(e.g., phone number) to which the {@link Connection} is to
+         *                connect.
+         */
+        public Builder setAddress(Uri address) {
+            this.mAddress = address;
+            return this;
+        }
+
+        /**
+         * Sets the extras bundle for the resulting {@link ConnectionRequest}
+         * @param extras Application-specific extra data.
+         */
+        public Builder setExtras(Bundle extras) {
+            this.mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Sets the video state for the resulting {@link ConnectionRequest}
+         * @param videoState Determines the video state for the connection.
+         */
+        public Builder setVideoState(int videoState) {
+            this.mVideoState = videoState;
+            return this;
+        }
+
+        /**
+         * Sets the Telecom call ID for the resulting {@link ConnectionRequest}
+         * @param telecomCallId The telecom call ID.
+         */
+        public Builder setTelecomCallId(String telecomCallId) {
+            this.mTelecomCallId = telecomCallId;
+            return this;
+        }
+
+        /**
+         * Sets shouldShowIncomingUi for the resulting {@link ConnectionRequest}
+         * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
+         *                                 {@code true} if the {@link ConnectionService} should show
+         *                                 its own incoming call UI for an incoming call.  When
+         *                                 {@code false}, Telecom shows the incoming call UI.
+         */
+        public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+            this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
+            return this;
+        }
+
+        /**
+         * Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
+         * resulting {@link ConnectionRequest}
+         * @param rttPipeFromInCall The data pipe to read from.
+         */
+        public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+            this.mRttPipeFromInCall = rttPipeFromInCall;
+            return this;
+        }
+
+        /**
+         * Sets the RTT pipe for transferring text out of {@link ConnectionService} for the
+         * resulting {@link ConnectionRequest}
+         * @param rttPipeToInCall The data pipe to write to.
+         */
+        public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+            this.mRttPipeToInCall = rttPipeToInCall;
+            return this;
+        }
+
+        public ConnectionRequest build() {
+            return new ConnectionRequest(
+                    mAccountHandle,
+                    mAddress,
+                    mExtras,
+                    mVideoState,
+                    mTelecomCallId,
+                    mShouldShowIncomingCallUi,
+                    mRttPipeFromInCall,
+                    mRttPipeToInCall);
+        }
+    }
+
     private final PhoneAccountHandle mAccountHandle;
     private final Uri mAddress;
     private final Bundle mExtras;
     private final int mVideoState;
     private final String mTelecomCallId;
     private final boolean mShouldShowIncomingCallUi;
+    private final ParcelFileDescriptor mRttPipeToInCall;
+    private final ParcelFileDescriptor mRttPipeFromInCall;
 
     /**
      * @param accountHandle The accountHandle which should be used to place the call.
@@ -44,7 +153,7 @@
             PhoneAccountHandle accountHandle,
             Uri handle,
             Bundle extras) {
-        this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false);
+        this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false, null, null);
     }
 
     /**
@@ -58,7 +167,7 @@
             Uri handle,
             Bundle extras,
             int videoState) {
-        this(accountHandle, handle, extras, videoState, null, false);
+        this(accountHandle, handle, extras, videoState, null, false, null, null);
     }
 
     /**
@@ -80,12 +189,27 @@
             int videoState,
             String telecomCallId,
             boolean shouldShowIncomingCallUi) {
+        this(accountHandle, handle, extras, videoState, telecomCallId,
+                shouldShowIncomingCallUi, null, null);
+    }
+
+    private ConnectionRequest(
+            PhoneAccountHandle accountHandle,
+            Uri handle,
+            Bundle extras,
+            int videoState,
+            String telecomCallId,
+            boolean shouldShowIncomingCallUi,
+            ParcelFileDescriptor rttPipeFromInCall,
+            ParcelFileDescriptor rttPipeToInCall) {
         mAccountHandle = accountHandle;
         mAddress = handle;
         mExtras = extras;
         mVideoState = videoState;
         mTelecomCallId = telecomCallId;
         mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
+        mRttPipeFromInCall = rttPipeFromInCall;
+        mRttPipeToInCall = rttPipeToInCall;
     }
 
     private ConnectionRequest(Parcel in) {
@@ -95,6 +219,8 @@
         mVideoState = in.readInt();
         mTelecomCallId = in.readString();
         mShouldShowIncomingCallUi = in.readInt() == 1;
+        mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
+        mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
     }
 
     /**
@@ -149,6 +275,59 @@
         return mShouldShowIncomingCallUi;
     }
 
+    /**
+     * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
+     * service to the in-call UI. In order to obtain an
+     * {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use
+     * {@link android.os.ParcelFileDescriptor.AutoCloseInputStream}.
+     * Only text data encoded using UTF-8 should be written into this {@link ParcelFileDescriptor}.
+     * @return The {@link ParcelFileDescriptor} that should be used for communication.
+     * Do not un-hide -- only for use by Telephony
+     * @hide
+     */
+    public ParcelFileDescriptor getRttPipeToInCall() {
+        return mRttPipeToInCall;
+    }
+
+    /**
+     * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the in-call UI to
+     * the connection service. In order to obtain an
+     * {@link java.io.OutputStream} from this {@link ParcelFileDescriptor}, use
+     * {@link android.os.ParcelFileDescriptor.AutoCloseOutputStream}.
+     * The contents of this {@link ParcelFileDescriptor} will consist solely of text encoded in
+     * UTF-8.
+     * @return The {@link ParcelFileDescriptor} that should be used for communication
+     * Do not un-hide -- only for use by Telephony
+     * @hide
+     */
+    public ParcelFileDescriptor getRttPipeFromInCall() {
+        return mRttPipeFromInCall;
+    }
+
+    /**
+     * Gets the {@link android.telecom.Connection.RttTextStream} object that should be used to
+     * send and receive RTT text to/from the in-call app.
+     * @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
+     * if this connection request is not requesting an RTT session upon connection establishment.
+     * @hide
+     */
+    public Connection.RttTextStream getRttTextStream() {
+        if (isRequestingRtt()) {
+            return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Convenience method for determining whether the ConnectionRequest is requesting an RTT session
+     * @return {@code true} if RTT is requested, {@code false} otherwise.
+     * @hide
+     */
+    public boolean isRequestingRtt() {
+        return mRttPipeFromInCall != null && mRttPipeToInCall != null;
+    }
+
     @Override
     public String toString() {
         return String.format("ConnectionRequest %s %s",
@@ -186,5 +365,7 @@
         destination.writeInt(mVideoState);
         destination.writeString(mTelecomCallId);
         destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
+        destination.writeParcelable(mRttPipeFromInCall, 0);
+        destination.writeParcelable(mRttPipeToInCall, 0);
     }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index ce3144b..6e10029 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -98,6 +98,7 @@
     private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
     private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
     private static final String SESSION_CREATE_CONN = "CS.crCo";
+    private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF";
     private static final String SESSION_ABORT = "CS.ab";
     private static final String SESSION_ANSWER = "CS.an";
     private static final String SESSION_ANSWER_VIDEO = "CS.anV";
@@ -142,6 +143,7 @@
     private static final int MSG_PULL_EXTERNAL_CALL = 22;
     private static final int MSG_SEND_CALL_EVENT = 23;
     private static final int MSG_ON_EXTRAS_CHANGED = 24;
+    private static final int MSG_CREATE_CONNECTION_FAILED = 25;
 
     private static Connection sNullConnection;
 
@@ -211,6 +213,25 @@
         }
 
         @Override
+        public void createConnectionFailed(
+                String callId,
+                ConnectionRequest request,
+                boolean isIncoming,
+                Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_CREATE_CONN_FAILED);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = request;
+                args.arg3 = Log.createSubsession();
+                args.argi1 = isIncoming ? 1 : 0;
+                mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void abort(String callId, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_ABORT);
             try {
@@ -552,6 +573,35 @@
                     }
                     break;
                 }
+                case MSG_CREATE_CONNECTION_FAILED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+                            SESSION_CREATE_CONN_FAILED);
+                    try {
+                        final String id = (String) args.arg1;
+                        final ConnectionRequest request = (ConnectionRequest) args.arg2;
+                        final boolean isIncoming = args.argi1 == 1;
+                        if (!mAreAccountsInitialized) {
+                            Log.d(this, "Enqueueing pre-init request %s", id);
+                            mPreInitializationConnectionRequests.add(
+                                    new android.telecom.Logging.Runnable(
+                                            SESSION_HANDLER + SESSION_CREATE_CONN_FAILED + ".pICR",
+                                            null /*lock*/) {
+                                        @Override
+                                        public void loggedRun() {
+                                            createConnectionFailed(id, request, isIncoming);
+                                        }
+                                    }.prepare());
+                        } else {
+                            Log.i(this, "createConnectionFailed %s", id);
+                            createConnectionFailed(id, request, isIncoming);
+                        }
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_ABORT: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
@@ -1175,6 +1225,17 @@
         }
     }
 
+    private void createConnectionFailed(final String callId, final ConnectionRequest request,
+            boolean isIncoming) {
+
+        Log.i(this, "createConnectionFailed %s", callId);
+        if (isIncoming) {
+            onCreateIncomingConnectionFailed(request);
+        } else {
+            onCreateOutgoingConnectionFailed(request);
+        }
+    }
+
     private void abort(String callId) {
         Log.d(this, "abort %s", callId);
         findConnectionForAction(callId, "abort").onAbort();
@@ -1756,7 +1817,13 @@
      */
     private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
         String id;
-        if (handle == null) {
+
+        if (connection.getExtras() != null && connection.getExtras()
+                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+            id = connection.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
+            Log.d(this, "addExistingConnectionInternal - conn %s reusing original id %s",
+                    connection.getTelecomCallId(), id);
+        } else if (handle == null) {
             // If no phone account handle was provided, we cannot be sure the call ID is unique,
             // so just use a random UUID.
             id = UUID.randomUUID().toString();
@@ -1790,13 +1857,21 @@
     }
 
     private String addConferenceInternal(Conference conference) {
+        String originalId = null;
+        if (conference.getExtras() != null && conference.getExtras()
+                .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
+            originalId = conference.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
+            Log.d(this, "addConferenceInternal: conf %s reusing original id %s",
+                    conference.getTelecomCallId(),
+                    originalId);
+        }
         if (mIdByConference.containsKey(conference)) {
             Log.w(this, "Re-adding an existing conference: %s.", conference);
         } else if (conference != null) {
             // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
             // cannot determine a ConnectionService class name to associate with the ID, so use
             // a unique UUID (for now).
-            String id = UUID.randomUUID().toString();
+            String id = originalId == null ? UUID.randomUUID().toString() : originalId;
             mConferenceById.put(id, conference);
             mIdByConference.put(conference, id);
             conference.addListener(mConferenceListener);
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 3f270d9..d640b1d 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -34,7 +34,7 @@
  * <p>
  * The adapter will stop functioning when there are no more calls.
  *
- * {@hide}
+ * @hide
  */
 public final class InCallAdapter {
     private final IInCallAdapter mAdapter;
@@ -375,4 +375,48 @@
         } catch (RemoteException ignored) {
         }
     }
+
+    /**
+     * Sends an RTT upgrade request to the remote end of the connection.
+     */
+    public void sendRttRequest() {
+        try {
+            mAdapter.sendRttRequest();
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Responds to an RTT upgrade request initiated from the remote end.
+     *
+     * @param id the ID of the request as specified by Telecom
+     * @param accept Whether the request should be accepted.
+     */
+    public void respondToRttRequest(int id, boolean accept) {
+        try {
+            mAdapter.respondToRttRequest(id, accept);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Instructs Telecom to shut down the RTT communication channel.
+     */
+    public void stopRtt() {
+        try {
+            mAdapter.stopRtt();
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Sets the RTT audio mode.
+     * @param mode the desired RTT audio mode
+     */
+    public void setRttMode(int mode) {
+        try {
+            mAdapter.setRttMode(mode);
+        } catch (RemoteException ignored) {
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 69de89d..4bc64c0 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -76,6 +76,7 @@
     private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
     private static final int MSG_SILENCE_RINGER = 8;
     private static final int MSG_ON_CONNECTION_EVENT = 9;
+    private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
 
     /** Default Handler used to consolidate binder method calls onto a single thread. */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -87,7 +88,8 @@
 
             switch (msg.what) {
                 case MSG_SET_IN_CALL_ADAPTER:
-                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
+                    String callingPackage = getApplicationContext().getOpPackageName();
+                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj), callingPackage);
                     mPhone.addListener(mPhoneListener);
                     onPhoneCreated(mPhone);
                     break;
@@ -132,6 +134,12 @@
                     }
                     break;
                 }
+                case MSG_ON_RTT_UPGRADE_REQUEST: {
+                    String callId = (String) msg.obj;
+                    int requestId = msg.arg1;
+                    mPhone.internalOnRttUpgradeRequest(callId, requestId);
+                    break;
+                }
                 default:
                     break;
             }
@@ -197,6 +205,11 @@
             args.arg3 = extras;
             mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
         }
+
+        @Override
+        public void onRttUpgradeRequest(String callId, int id) {
+            mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget();
+        }
     }
 
     private Phone.Listener mPhoneListener = new Phone.Listener() {
@@ -664,7 +677,8 @@
              *      {@link Connection.VideoProvider#SESSION_EVENT_TX_START},
              *      {@link Connection.VideoProvider#SESSION_EVENT_TX_STOP},
              *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
-             *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY}.
+             *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_READY},
+             *      {@link Connection.VideoProvider#SESSION_EVENT_CAMERA_PERMISSION_ERROR}.
              */
             public abstract void onCallSessionEvent(int event);
 
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index f7a6595..975aa5a 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -50,6 +50,8 @@
     private final boolean mIsVideoCallProviderChanged;
     private final IVideoProvider mVideoCallProvider;
     private VideoCallImpl mVideoCall;
+    private final boolean mIsRttCallChanged;
+    private final ParcelableRttCall mRttCall;
     private final String mParentCallId;
     private final List<String> mChildCallIds;
     private final StatusHints mStatusHints;
@@ -75,6 +77,8 @@
             PhoneAccountHandle accountHandle,
             boolean isVideoCallProviderChanged,
             IVideoProvider videoCallProvider,
+            boolean isRttCallChanged,
+            ParcelableRttCall rttCall,
             String parentCallId,
             List<String> childCallIds,
             StatusHints statusHints,
@@ -98,6 +102,8 @@
         mAccountHandle = accountHandle;
         mIsVideoCallProviderChanged = isVideoCallProviderChanged;
         mVideoCallProvider = videoCallProvider;
+        mIsRttCallChanged = isRttCallChanged;
+        mRttCall = rttCall;
         mParentCallId = parentCallId;
         mChildCallIds = childCallIds;
         mStatusHints = statusHints;
@@ -190,10 +196,10 @@
 
      * @return The video call.
      */
-    public VideoCallImpl getVideoCallImpl() {
+    public VideoCallImpl getVideoCallImpl(String callingPackageName) {
         if (mVideoCall == null && mVideoCallProvider != null) {
             try {
-                mVideoCall = new VideoCallImpl(mVideoCallProvider);
+                mVideoCall = new VideoCallImpl(mVideoCallProvider, callingPackageName);
             } catch (RemoteException ignored) {
                 // Ignore RemoteException.
             }
@@ -202,6 +208,18 @@
         return mVideoCall;
     }
 
+    public boolean getIsRttCallChanged() {
+        return mIsRttCallChanged;
+    }
+
+    /**
+     * RTT communication channel information
+     * @return The ParcelableRttCall
+     */
+    public ParcelableRttCall getParcelableRttCall() {
+        return mRttCall;
+    }
+
     /**
      * The conference call to which this call is conferenced. Null if not conferenced.
      */
@@ -301,6 +319,8 @@
             Bundle intentExtras = source.readBundle(classLoader);
             Bundle extras = source.readBundle(classLoader);
             int supportedAudioRoutes = source.readInt();
+            boolean isRttCallChanged = source.readByte() == 1;
+            ParcelableRttCall rttCall = source.readParcelable(classLoader);
             return new ParcelableCall(
                     id,
                     state,
@@ -318,6 +338,8 @@
                     accountHandle,
                     isVideoCallProviderChanged,
                     videoCallProvider,
+                    isRttCallChanged,
+                    rttCall,
                     parentCallId,
                     childCallIds,
                     statusHints,
@@ -366,6 +388,8 @@
         destination.writeBundle(mIntentExtras);
         destination.writeBundle(mExtras);
         destination.writeInt(mSupportedAudioRoutes);
+        destination.writeByte((byte) (mIsRttCallChanged ? 1 : 0));
+        destination.writeParcelable(mRttCall, 0);
     }
 
     @Override
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl b/telecomm/java/android/telecom/ParcelableRttCall.aidl
similarity index 81%
copy from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
copy to telecomm/java/android/telecom/ParcelableRttCall.aidl
index 62d5603..4480710 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
+++ b/telecomm/java/android/telecom/ParcelableRttCall.aidl
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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.
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot2.pps;
+package android.telecom;
 
-parcelable HomeSP;
+/**
+ * {@hide}
+ */
+parcelable ParcelableRttCall;
diff --git a/telecomm/java/android/telecom/ParcelableRttCall.java b/telecomm/java/android/telecom/ParcelableRttCall.java
new file mode 100644
index 0000000..763e48b
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableRttCall.java
@@ -0,0 +1,88 @@
+/*
+ * 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.telecom;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Data container for information associated with the RTT connection on a call.
+ * @hide
+ */
+public class ParcelableRttCall implements Parcelable {
+    private final int mRttMode;
+    private final ParcelFileDescriptor mTransmitStream;
+    private final ParcelFileDescriptor mReceiveStream;
+
+    public ParcelableRttCall(
+            int rttMode,
+            ParcelFileDescriptor transmitStream,
+            ParcelFileDescriptor receiveStream) {
+        mRttMode = rttMode;
+        mTransmitStream = transmitStream;
+        mReceiveStream = receiveStream;
+    }
+
+    protected ParcelableRttCall(Parcel in) {
+        mRttMode = in.readInt();
+        mTransmitStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+        mReceiveStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+    }
+
+    public static final Creator<ParcelableRttCall> CREATOR = new Creator<ParcelableRttCall>() {
+        @Override
+        public ParcelableRttCall createFromParcel(Parcel in) {
+            return new ParcelableRttCall(in);
+        }
+
+        @Override
+        public ParcelableRttCall[] newArray(int size) {
+            return new ParcelableRttCall[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRttMode);
+        dest.writeParcelable(mTransmitStream, flags);
+        dest.writeParcelable(mReceiveStream, flags);
+    }
+
+    public int getRttMode() {
+        return mRttMode;
+    }
+
+    public ParcelFileDescriptor getReceiveStream() {
+        return mReceiveStream;
+    }
+
+    public ParcelFileDescriptor getTransmitStream() {
+        return mTransmitStream;
+    }
+}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a4ef560..ebd04c7 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -125,13 +125,16 @@
 
     private boolean mCanAddCall = true;
 
-    Phone(InCallAdapter adapter) {
+    private final String mCallingPackage;
+
+    Phone(InCallAdapter adapter, String callingPackage) {
         mInCallAdapter = adapter;
+        mCallingPackage = callingPackage;
     }
 
     final void internalAddCall(ParcelableCall parcelableCall) {
         Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
-                parcelableCall.getState());
+                parcelableCall.getState(), mCallingPackage);
         mCallByTelecomCallId.put(parcelableCall.getId(), call);
         mCalls.add(call);
         checkCallTree(parcelableCall);
@@ -198,6 +201,13 @@
         }
     }
 
+    final void internalOnRttUpgradeRequest(String callId, int requestId) {
+        Call call = mCallByTelecomCallId.get(callId);
+        if (call != null) {
+            call.internalOnRttUpgradeRequest(requestId);
+        }
+    }
+
     /**
      * Called to destroy the phone and cleanup any lingering calls.
      */
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 845a103..3926e20 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -204,6 +204,18 @@
     public static final int CAPABILITY_SELF_MANAGED = 0x800;
 
     /**
+     * Flag indicating that this {@link PhoneAccount} is capable of making a call with an
+     * RTT (Real-time text) session.
+     * When set, Telecom will attempt to open an RTT session on outgoing calls that specify
+     * that they should be placed with an RTT session , and the in-call app will be displayed
+     * with text entry fields for RTT. Likewise, the in-call app can request that an RTT
+     * session be opened during a call if this bit is set.
+     */
+    public static final int CAPABILITY_RTT = 0x1000;
+
+    /* NEXT CAPABILITY: 0x2000 */
+
+    /**
      * URI scheme for telephone number URIs.
      */
     public static final String SCHEME_TEL = "tel";
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index 4bff688..502b7c0 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -311,6 +311,9 @@
 
     /** @hide */
     void putExtras(final Bundle extras) {
+        if (extras == null) {
+            return;
+        }
         if (mExtras == null) {
             mExtras = new Bundle();
         }
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 11842a0..77e0e54 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -408,6 +408,8 @@
 
         private final IVideoProvider mVideoProviderBinder;
 
+        private final String mCallingPackage;
+
         /**
          * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
          * load factor before resizing, 1 means we only expect a single thread to
@@ -416,8 +418,9 @@
         private final Set<Callback> mCallbacks = Collections.newSetFromMap(
                 new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1));
 
-        VideoProvider(IVideoProvider videoProviderBinder) {
+        VideoProvider(IVideoProvider videoProviderBinder, String callingPackage) {
             mVideoProviderBinder = videoProviderBinder;
+            mCallingPackage = callingPackage;
             try {
                 mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
             } catch (RemoteException e) {
@@ -452,7 +455,7 @@
          */
         public void setCamera(String cameraId) {
             try {
-                mVideoProviderBinder.setCamera(cameraId);
+                mVideoProviderBinder.setCamera(cameraId, mCallingPackage);
             } catch (RemoteException e) {
             }
         }
@@ -628,7 +631,7 @@
      * @hide
      */
     RemoteConnection(String callId, IConnectionService connectionService,
-            ParcelableConnection connection) {
+            ParcelableConnection connection, String callingPackage) {
         mConnectionId = callId;
         mConnectionService = connectionService;
         mConnected = true;
@@ -640,7 +643,7 @@
         mVideoState = connection.getVideoState();
         IVideoProvider videoProvider = connection.getVideoProvider();
         if (videoProvider != null) {
-            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+            mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage);
         } else {
             mVideoProvider = null;
         }
@@ -651,6 +654,14 @@
         mCallerDisplayName = connection.getCallerDisplayName();
         mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
         mConference = null;
+        putExtras(connection.getExtras());
+
+        // Stash the original connection ID as it exists in the source ConnectionService.
+        // Telecom will use this to avoid adding duplicates later.
+        // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
+        Bundle newExtras = new Bundle();
+        newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
+        putExtras(newExtras);
     }
 
     /**
@@ -1350,6 +1361,9 @@
 
     /** @hide */
     void putExtras(final Bundle extras) {
+        if (extras == null) {
+            return;
+        }
         if (mExtras == null) {
             mExtras = new Bundle();
         }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index fe14003..60a40f5 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -219,18 +219,27 @@
                     conference.addConnection(c);
                 }
             }
-
             if (conference.getConnections().size() == 0) {
                 // A conference was created, but none of its connections are ones that have been
                 // created by, and therefore being tracked by, this remote connection service. It
                 // is of no interest to us.
+                Log.d(this, "addConferenceCall - skipping");
                 return;
             }
 
             conference.setState(parcel.getState());
             conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
             conference.setConnectionProperties(parcel.getConnectionProperties());
+            conference.putExtras(parcel.getExtras());
             mConferenceById.put(callId, conference);
+
+            // Stash the original connection ID as it exists in the source ConnectionService.
+            // Telecom will use this to avoid adding duplicates later.
+            // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information.
+            Bundle newExtras = new Bundle();
+            newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
+            conference.putExtras(newExtras);
+
             conference.registerCallback(new RemoteConference.Callback() {
                 @Override
                 public void onDestroyed(RemoteConference c) {
@@ -274,9 +283,13 @@
         @Override
         public void setVideoProvider(String callId, IVideoProvider videoProvider,
                 Session.Info sessionInfo) {
+
+            String callingPackage = mOurConnectionServiceImpl.getApplicationContext()
+                    .getOpPackageName();
             RemoteConnection.VideoProvider remoteVideoProvider = null;
             if (videoProvider != null) {
-                remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider);
+                remoteVideoProvider = new RemoteConnection.VideoProvider(videoProvider,
+                        callingPackage);
             }
             findConnectionForAction(callId, "setVideoProvider")
                     .setVideoProvider(remoteVideoProvider);
@@ -342,11 +355,19 @@
         @Override
         public void addExistingConnection(String callId, ParcelableConnection connection,
                 Session.Info sessionInfo) {
-            // TODO: add contents of this method
-            RemoteConnection remoteConnction = new RemoteConnection(callId,
-                    mOutgoingConnectionServiceRpc, connection);
-
-            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
+            String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
+                    getOpPackageName();
+            RemoteConnection remoteConnection = new RemoteConnection(callId,
+                    mOutgoingConnectionServiceRpc, connection, callingPackage);
+            mConnectionById.put(callId, remoteConnection);
+            remoteConnection.registerCallback(new RemoteConnection.Callback() {
+                @Override
+                public void onDestroyed(RemoteConnection connection) {
+                    mConnectionById.remove(callId);
+                    maybeDisconnectAdapter();
+                }
+            });
+            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnection);
         }
 
         @Override
@@ -429,11 +450,14 @@
             ConnectionRequest request,
             boolean isIncoming) {
         final String id = UUID.randomUUID().toString();
-        final ConnectionRequest newRequest = new ConnectionRequest(
-                request.getAccountHandle(),
-                request.getAddress(),
-                request.getExtras(),
-                request.getVideoState());
+        final ConnectionRequest newRequest = new ConnectionRequest.Builder()
+                .setAccountHandle(request.getAccountHandle())
+                .setAddress(request.getAddress())
+                .setExtras(request.getExtras())
+                .setVideoState(request.getVideoState())
+                .setRttPipeFromInCall(request.getRttPipeFromInCall())
+                .setRttPipeToInCall(request.getRttPipeToInCall())
+                .build();
         try {
             if (mConnectionById.isEmpty()) {
                 mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ba7b6a1..6807ef4 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,23 @@
     public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
 
     /**
+     * The number of milliseconds that Telecom should wait after disconnecting a call via the
+     * ACTION_NEW_OUTGOING_CALL broadcast, in order to wait for the app which cancelled the call
+     * to make a new one.
+     * @hide
+     */
+    public static final String EXTRA_NEW_OUTGOING_CALL_CANCEL_TIMEOUT =
+            "android.telecom.extra.NEW_OUTGOING_CALL_CANCEL_TIMEOUT";
+
+    /**
+     * A boolean extra, which when set on the {@link Intent#ACTION_CALL} intent or on the bundle
+     * passed into {@link #placeCall(Uri, Bundle)}, indicates that the call should be initiated with
+     * an RTT session open. See {@link android.telecom.Call.RttCall} for more information on RTT.
+     */
+    public static final String EXTRA_START_CALL_WITH_RTT =
+            "android.telecom.extra.START_CALL_WITH_RTT";
+
+    /**
      * A boolean meta-data value indicating whether an {@link InCallService} implements an
      * in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which
      * would also like to replace the in-call interface should set this meta-data to {@code true} in
@@ -1517,6 +1534,10 @@
      *      otherwise.
      */
     public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+        if (phoneAccountHandle == null) {
+            return false;
+        }
+
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index e54abee..d8ede5c 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -43,6 +43,7 @@
     private VideoCall.Callback mCallback;
     private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
     private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+    private final String mCallingPackageName;
 
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
@@ -197,12 +198,13 @@
 
     private Handler mHandler;
 
-    VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
+    VideoCallImpl(IVideoProvider videoProvider, String callingPackageName) throws RemoteException {
         mVideoProvider = videoProvider;
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
 
         mBinder = new VideoCallListenerBinder();
         mVideoProvider.addVideoCallback(mBinder);
+        mCallingPackageName = callingPackageName;
     }
 
     public void destroy() {
@@ -240,7 +242,8 @@
     /** {@inheritDoc} */
     public void setCamera(String cameraId) {
         try {
-            mVideoProvider.setCamera(cameraId);
+            Log.w(this, "setCamera: cameraId=%s, calling=%s", cameraId, mCallingPackageName);
+            mVideoProvider.setCamera(cameraId, mCallingPackageName);
         } catch (RemoteException e) {
         }
     }
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 216603c..e0e3a08 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -235,7 +235,7 @@
         StringBuilder sb = new StringBuilder();
         sb.append("Audio");
 
-        if (isAudioOnly(videoState)) {
+        if (videoState == STATE_AUDIO_ONLY) {
             sb.append(" Only");
         } else {
             if (isTransmissionEnabled(videoState)) {
@@ -256,6 +256,9 @@
 
     /**
      * Indicates whether the video state is audio only.
+     * <p>
+     * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
+     * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
      *
      * @param videoState The video state.
      * @return {@code True} if the video state is audio only, {@code false} otherwise.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 8a27675..20feba7 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -46,6 +46,9 @@
             boolean isUnknown,
             in Session.Info sessionInfo);
 
+    void createConnectionFailed(String callId, in ConnectionRequest request, boolean isIncoming,
+            in Session.Info sessionInfo);
+
     void abort(String callId, in Session.Info sessionInfo);
 
     void answerVideo(String callId, int videoState, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 49f9b3b..47c3e6c 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -69,4 +69,12 @@
     void putExtras(String callId, in Bundle extras);
 
     void removeExtras(String callId, in List<String> keys);
+
+    void sendRttRequest();
+
+    void respondToRttRequest(int id, boolean accept);
+
+    void stopRtt();
+
+    void setRttMode(int mode);
 }
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 3e43fe2..1f92e0c 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -50,4 +50,6 @@
     void silenceRinger();
 
     void onConnectionEvent(String callId, String event, in Bundle extras);
+
+    void onRttUpgradeRequest(String callId, int id);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 6ca0bc5..d9465dc 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -259,4 +259,9 @@
      * @see TelecomServiceImpl#isOutgoingCallPermitted
      */
     boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
+
+    /**
+     * @see TelecomServiceImpl#waitOnHandler
+     */
+    void waitOnHandlers();
 }
diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
index 68e5fd4..a109e90 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -30,7 +30,7 @@
 
     void removeVideoCallback(IBinder videoCallbackBinder);
 
-    void setCamera(String cameraId);
+    void setCamera(String cameraId, in String mCallingPackageName);
 
     void setPreviewSurface(in Surface surface);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d7cd07a..02774b3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -817,7 +817,7 @@
 
     /**
      * Defines carrier-specific actions which act upon
-     * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
+     * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
      * default carrier app
      * Format: "CARRIER_ACTION_IDX, ..."
      * Where {@code CARRIER_ACTION_IDX} is an integer defined in
@@ -832,7 +832,7 @@
 
     /**
      * Defines carrier-specific actions which act upon
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
      * and configured signal args:
      * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
      * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
@@ -873,11 +873,11 @@
      * @see com.android.internal.telephony.TelephonyIntents
      * Example:
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
-     * android.intent.action.CARRIER_SIGNAL_REDIRECTED,
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED,
+     * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
      * </item>
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
      * </item>
      * @hide
      */
@@ -892,11 +892,11 @@
      * @see com.android.internal.telephony.TelephonyIntents
      * Example:
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+     * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
      * </item>
      * <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
      * </item>
      * @hide
      */
@@ -1064,6 +1064,9 @@
      * and {@code NEW_CODE} is the new {@code ImsReasonInfo#CODE_*} which this combination of
      * original code and message shall be remapped to.
      *
+     * Note: If {@code *} is specified for the original code, any ImsReasonInfo with the matching
+     * {@code MESSAGE} will be remapped to {@code NEW_CODE}.
+     *
      * Example: "501|call completion elsewhere|1014"
      * When the {@link ImsReasonInfo#getCode()} is {@link ImsReasonInfo#CODE_USER_TERMINATED} and
      * the {@link ImsReasonInfo#getExtraMessage()} is {@code "call completion elsewhere"},
@@ -1116,6 +1119,14 @@
     public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
             "editable_wfc_roaming_mode_bool";
 
+    /**
+     * Indicates whether the carrier supports 3gpp call forwarding MMI codes while roaming. If
+     * false, the user will be notified that call forwarding is not available when the MMI code
+     * fails.
+     */
+    public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL =
+            "support_3gpp_call_forwarding_while_roaming_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1290,7 +1301,7 @@
         sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
                 new String[]{
                         "com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
-                                "android.intent.action.CARRIER_SIGNAL_REDIRECTED"
+                                "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
                 });
         sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
 
@@ -1320,6 +1331,7 @@
         sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
         sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
     }
 
     /**
diff --git a/telephony/java/android/telephony/ClientRequestStats.aidl b/telephony/java/android/telephony/ClientRequestStats.aidl
new file mode 100644
index 0000000..206ee70
--- /dev/null
+++ b/telephony/java/android/telephony/ClientRequestStats.aidl
@@ -0,0 +1,22 @@
+/*
+** 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;
+
+/**
+ * @hide
+ */
+parcelable  ClientRequestStats;
diff --git a/telephony/java/android/telephony/ClientRequestStats.java b/telephony/java/android/telephony/ClientRequestStats.java
new file mode 100644
index 0000000..381c847
--- /dev/null
+++ b/telephony/java/android/telephony/ClientRequestStats.java
@@ -0,0 +1,175 @@
+/*
+ * 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.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.TelephonyHistogram;
+import android.util.SparseArray;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parcelable class to store Client request statistics information.
+ *
+ * @hide
+ */
+public final class ClientRequestStats implements Parcelable {
+    public static final Parcelable.Creator<ClientRequestStats> CREATOR =
+            new Parcelable.Creator<ClientRequestStats>() {
+
+                public ClientRequestStats createFromParcel(Parcel in) {
+                    return new ClientRequestStats(in);
+                }
+
+                public ClientRequestStats[] newArray(int size) {
+                    return new ClientRequestStats[size];
+                }
+            };
+    private static final int REQUEST_HISTOGRAM_BUCKET_COUNT = 5;
+    private String mCallingPackage;
+    /* completed requests wake lock time in milli seconds */
+    private long mCompletedRequestsWakelockTime = 0;
+    private long mCompletedRequestsCount = 0;
+    private long mPendingRequestsWakelockTime = 0;
+    private long mPendingRequestsCount = 0;
+    private SparseArray<TelephonyHistogram> mRequestHistograms =
+            new SparseArray<TelephonyHistogram>();
+
+    public ClientRequestStats(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public ClientRequestStats() {
+    }
+
+    public ClientRequestStats(ClientRequestStats clientRequestStats) {
+        mCallingPackage = clientRequestStats.getCallingPackage();
+        mCompletedRequestsCount = clientRequestStats.getCompletedRequestsCount();
+        mCompletedRequestsWakelockTime = clientRequestStats.getCompletedRequestsWakelockTime();
+        mPendingRequestsCount = clientRequestStats.getPendingRequestsCount();
+        mPendingRequestsWakelockTime = clientRequestStats.getPendingRequestsWakelockTime();
+
+        List<TelephonyHistogram> list = clientRequestStats.getRequestHistograms();
+        for (TelephonyHistogram entry : list) {
+            mRequestHistograms.put(entry.getId(), entry);
+        }
+    }
+
+    public String getCallingPackage() {
+        return mCallingPackage;
+    }
+
+    public void setCallingPackage(String mCallingPackage) {
+        this.mCallingPackage = mCallingPackage;
+    }
+
+    public long getCompletedRequestsWakelockTime() {
+        return mCompletedRequestsWakelockTime;
+    }
+
+    public void addCompletedWakelockTime(long completedRequestsWakelockTime) {
+        this.mCompletedRequestsWakelockTime += completedRequestsWakelockTime;
+    }
+
+    public long getPendingRequestsWakelockTime() {
+        return mPendingRequestsWakelockTime;
+    }
+
+    public void setPendingRequestsWakelockTime(long pendingRequestsWakelockTime) {
+        this.mPendingRequestsWakelockTime = pendingRequestsWakelockTime;
+    }
+
+    public long getCompletedRequestsCount() {
+        return mCompletedRequestsCount;
+    }
+
+    public void incrementCompletedRequestsCount() {
+        this.mCompletedRequestsCount++;
+    }
+
+    public long getPendingRequestsCount() {
+        return mPendingRequestsCount;
+    }
+
+    public void setPendingRequestsCount(long pendingRequestsCount) {
+        this.mPendingRequestsCount = pendingRequestsCount;
+    }
+
+    public List<TelephonyHistogram> getRequestHistograms() {
+        List<TelephonyHistogram> list;
+        synchronized (mRequestHistograms) {
+            list = new ArrayList<>(mRequestHistograms.size());
+            for (int i = 0; i < mRequestHistograms.size(); i++) {
+                TelephonyHistogram entry = new TelephonyHistogram(mRequestHistograms.valueAt(i));
+                list.add(entry);
+            }
+        }
+        return list;
+    }
+
+    public void updateRequestHistograms(int requestId, int time) {
+        synchronized (mRequestHistograms) {
+            TelephonyHistogram entry = mRequestHistograms.get(requestId);
+            if (entry == null) {
+                entry = new TelephonyHistogram(TelephonyHistogram.TELEPHONY_CATEGORY_RIL,
+                        requestId, REQUEST_HISTOGRAM_BUCKET_COUNT);
+                mRequestHistograms.put(requestId, entry);
+            }
+            entry.addTimeTaken(time);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ClientRequestStats{" +
+                "mCallingPackage='" + mCallingPackage + '\'' +
+                ", mCompletedRequestsWakelockTime=" + mCompletedRequestsWakelockTime +
+                ", mCompletedRequestsCount=" + mCompletedRequestsCount +
+                ", mPendingRequestsWakelockTime=" + mPendingRequestsWakelockTime +
+                ", mPendingRequestsCount=" + mPendingRequestsCount +
+                '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public void readFromParcel(Parcel in) {
+        mCallingPackage = in.readString();
+        mCompletedRequestsWakelockTime = in.readLong();
+        mCompletedRequestsCount = in.readLong();
+        mPendingRequestsWakelockTime = in.readLong();
+        mPendingRequestsCount = in.readLong();
+        ArrayList<TelephonyHistogram> requestHistograms = new ArrayList<TelephonyHistogram>();
+        in.readTypedList(requestHistograms, TelephonyHistogram.CREATOR);
+        for (TelephonyHistogram h : requestHistograms) {
+            mRequestHistograms.put(h.getId(), h);
+        }
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mCallingPackage);
+        dest.writeLong(mCompletedRequestsWakelockTime);
+        dest.writeLong(mCompletedRequestsCount);
+        dest.writeLong(mPendingRequestsWakelockTime);
+        dest.writeLong(mPendingRequestsCount);
+        dest.writeTypedList(getRequestHistograms());
+    }
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 811c996..6a081d0 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -240,23 +240,19 @@
      */
     public static final int IMEI_NOT_ACCEPTED = 57;
 
+    /**
+     * A call over WIFI was disconnected because the WIFI signal was lost or became too degraded to
+     * continue the call.
+     */
+    public static final int WIFI_LOST = 59;
+
     //*********************************************************************************************
     // When adding a disconnect type:
-    // 1) Please assign the new type the next id value below.
-    // 2) Increment the next id value below to a new value.
-    // 3) Update MAXIMUM_VALID_VALUE to the new disconnect type.
-    // 4) Update toString() with the newly added disconnect type.
-    // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
+    // 1) Update toString() with the newly added disconnect type.
+    // 2) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
     //
-    // NextId: 58
     //*********************************************************************************************
 
-    /** Smallest valid value for call disconnect codes. */
-    public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
-
-    /** Largest valid value for call disconnect codes. */
-    public static final int MAXIMUM_VALID_VALUE = IMEI_NOT_ACCEPTED;
-
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
         // Do nothing.
@@ -379,6 +375,8 @@
             return "DIALED_ON_WRONG_SLOT";
         case IMEI_NOT_ACCEPTED:
             return "IMEI_NOT_ACCEPTED";
+        case WIFI_LOST:
+            return "WIFI_LOST";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 152b868..38cffae 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1139,6 +1139,8 @@
 
     private static final String KOREA_ISO_COUNTRY_CODE = "KR";
 
+    private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
     /**
      * Breaks the given number down and formats it according to the rules
      * for the country the number is from.
@@ -1459,15 +1461,25 @@
         String result = null;
         try {
             PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
-            /**
-             * Need to reformat any local Korean phone numbers (when the user is in Korea) with
-             * country code to corresponding national format which would replace the leading
-             * +82 with 0.
-             */
-            if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
+
+            if (KOREA_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
                     (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
                     (pn.getCountryCodeSource() ==
                             PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+                /**
+                 * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+                 * country code to corresponding national format which would replace the leading
+                 * +82 with 0.
+                 */
+                result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+            } else if (JAPAN_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
+                    pn.getCountryCode() == util.getCountryCodeForRegion(JAPAN_ISO_COUNTRY_CODE) &&
+                    (pn.getCountryCodeSource() ==
+                            PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+                /**
+                 * Need to reformat Japanese phone numbers (when user is in Japan) with the national
+                 * dialing format.
+                 */
                 result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
             } else {
                 result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 32f487b..afff6d5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,17 +20,9 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.telephony.SubscriptionManager;
-import android.telephony.CellLocation;
-import android.telephony.CellInfo;
-import android.telephony.VoLteServiceState;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.PreciseCallState;
-import android.telephony.PreciseDataConnectionState;
 
 import com.android.internal.telephony.IPhoneStateListener;
+
 import java.util.List;
 import java.lang.ref.WeakReference;
 
@@ -216,7 +208,9 @@
      *
      * @see #onOemHookRawEvent
      * @hide
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;
 
     /**
@@ -228,6 +222,38 @@
      */
     public static final int LISTEN_CARRIER_NETWORK_CHANGE                   = 0x00010000;
 
+    /**
+     *  Listen for changes to the sim voice activation state
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+     *  {@more}
+     *  Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+     *  fully activated
+     *
+     *  @see #onVoiceActivationStateChanged
+     *  @hide
+     */
+    public static final int LISTEN_VOICE_ACTIVATION_STATE                   = 0x00020000;
+
+    /**
+     *  Listen for changes to the sim data activation state
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+     *  @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+     *  {@more}
+     *  Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+     *  fully activated
+     *
+     *  @see #onDataActivationStateChanged
+     *  @hide
+     */
+    public static final int LISTEN_DATA_ACTIVATION_STATE                   = 0x00040000;
+
      /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -327,6 +353,12 @@
                     case LISTEN_VOLTE_STATE:
                         PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
                         break;
+                    case LISTEN_VOICE_ACTIVATION_STATE:
+                        PhoneStateListener.this.onVoiceActivationStateChanged((int)msg.obj);
+                        break;
+                    case LISTEN_DATA_ACTIVATION_STATE:
+                        PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
+                        break;
                     case LISTEN_OEM_HOOK_RAW_EVENT:
                         PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
                         break;
@@ -506,6 +538,24 @@
     }
 
     /**
+     * Callback invoked when the SIM voice activation state has changed
+     * @param state is the current SIM voice activation state
+     * @hide
+     */
+    public void onVoiceActivationStateChanged(int state) {
+
+    }
+
+    /**
+     * Callback invoked when the SIM data activation state has changed
+     * @param state is the current SIM data activation state
+     * @hide
+     */
+    public void onDataActivationStateChanged(int state) {
+
+    }
+
+    /**
      * Callback invoked when OEM hook raw event is received. Requires
      * the READ_PRIVILEGED_PHONE_STATE permission.
      * @param rawData is the byte array of the OEM hook raw data.
@@ -619,6 +669,14 @@
             send(LISTEN_VOLTE_STATE, 0, 0, lteState);
         }
 
+        public void onVoiceActivationStateChanged(int activationState) {
+            send(LISTEN_VOICE_ACTIVATION_STATE, 0, 0, activationState);
+        }
+
+        public void onDataActivationStateChanged(int activationState) {
+            send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
+        }
+
         public void onOemHookRawEvent(byte[] rawData) {
             send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1554868..8479f88 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -39,6 +39,7 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.ClientRequestStats;
 import android.telephony.TelephonyHistogram;
 import android.telephony.ims.feature.ImsFeature;
 import android.util.Log;
@@ -2725,6 +2726,148 @@
     }
 
     /**
+     * Initial SIM activation state, unknown. Not set by any carrier apps.
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0;
+
+    /**
+     * indicate SIM is under activation procedure now.
+     * intermediate state followed by another state update with activation procedure result:
+     * @see #SIM_ACTIVATION_STATE_ACTIVATED
+     * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see #SIM_ACTIVATION_STATE_RESTRICTED
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1;
+
+    /**
+     * Indicate SIM has been successfully activated with full service
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2;
+
+    /**
+     * Indicate SIM has been deactivated by the carrier so that service is not available
+     * and requires activation service to enable services.
+     * Carrier apps could be signalled to set activation state to deactivated if detected
+     * deactivated sim state and set it back to activated after successfully run activation service.
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3;
+
+    /**
+     * Restricted state indicate SIM has been activated but service are restricted.
+     * note this is currently available for data activation state. For example out of byte sim.
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4;
+
+    /**
+     * Sets the voice activation state for the given subscriber.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription id.
+     * @param activationState The voice activation state of the given subscriber.
+     * @see #SIM_ACTIVATION_STATE_UNKNOWN
+     * @see #SIM_ACTIVATION_STATE_ACTIVATING
+     * @see #SIM_ACTIVATION_STATE_ACTIVATED
+     * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+     * @hide
+     */
+    public void setVoiceActivationState(int subId, int activationState) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null)
+                telephony.setVoiceActivationState(subId, activationState);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+    }
+
+    /**
+     * Sets the data activation state for the given subscriber.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription id.
+     * @param activationState The data activation state of the given subscriber.
+     * @see #SIM_ACTIVATION_STATE_UNKNOWN
+     * @see #SIM_ACTIVATION_STATE_ACTIVATING
+     * @see #SIM_ACTIVATION_STATE_ACTIVATED
+     * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see #SIM_ACTIVATION_STATE_RESTRICTED
+     * @hide
+     */
+    public void setDataActivationState(int subId, int activationState) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null)
+                telephony.setDataActivationState(subId, activationState);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+    }
+
+    /**
+     * Returns the voice activation state for the given subscriber.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
+     * @param subId The subscription id.
+     *
+     * @return voiceActivationState for the given subscriber
+     * @see #SIM_ACTIVATION_STATE_UNKNOWN
+     * @see #SIM_ACTIVATION_STATE_ACTIVATING
+     * @see #SIM_ACTIVATION_STATE_ACTIVATED
+     * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+     * @hide
+     */
+    public int getVoiceActivationState(int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null)
+                return telephony.getVoiceActivationState(subId, getOpPackageName());
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return SIM_ACTIVATION_STATE_UNKNOWN;
+    }
+
+    /**
+     * Returns the data activation state for the given subscriber.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
+     * @param subId The subscription id.
+     *
+     * @return dataActivationState for the given subscriber
+     * @see #SIM_ACTIVATION_STATE_UNKNOWN
+     * @see #SIM_ACTIVATION_STATE_ACTIVATING
+     * @see #SIM_ACTIVATION_STATE_ACTIVATED
+     * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see #SIM_ACTIVATION_STATE_RESTRICTED
+     * @hide
+     */
+    public int getDataActivationState(int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null)
+                return telephony.getDataActivationState(subId, getOpPackageName());
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return SIM_ACTIVATION_STATE_UNKNOWN;
+    }
+
+    /**
      * Returns the voice mail count. Return 0 if unavailable, -1 if there are unread voice messages
      * but the count is unknown.
      * <p>
@@ -4897,7 +5040,9 @@
      *         0 request was handled succesfully, but no response data
      *         positive value success, data length of response
      * @hide
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
         try {
             ITelephony telephony = getITelephony();
@@ -5190,6 +5335,44 @@
     }
 
     /**
+     * Set SIM card power state. Request is equivalent to inserting or removing the card.
+     *
+     * @param powerUp True if powering up the SIM, otherwise powering down
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     *
+     * @hide
+     **/
+    public void setSimPowerState(boolean powerUp) {
+        setSimPowerStateForSlot(getDefaultSim(), powerUp);
+    }
+
+    /**
+     * Set SIM card power state. Request is equivalent to inserting or removing the card.
+     *
+     * @param slotId SIM slot id
+     * @param powerUp True if powering up the SIM, otherwise powering down
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     *
+     * @hide
+     **/
+    public void setSimPowerStateForSlot(int slotId, boolean powerUp) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setSimPowerStateForSlot(slotId, powerUp);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Permission error calling ITelephony#setSimPowerStateForSlot", e);
+        }
+    }
+
+    /**
      * Set baseband version for the default phone.
      *
      * @param version baseband version
@@ -5844,5 +6027,27 @@
             Log.e(TAG, "Error calling ITelephony#setPolicyDataEnabled", e);
         }
     }
+
+    /**
+     * Get Client request stats which will contain statistical information
+     * on each request made by client.
+     * Callers require either READ_PRIVILEGED_PHONE_STATE or
+     * READ_PHONE_STATE to retrieve the information.
+     * @param subId sub id
+     * @return List of Client Request Stats
+     * @hide
+     */
+    public List<ClientRequestStats> getClientRequestStats(int subId) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getClientRequestStats(getOpPackageName(), subId);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getClientRequestStats", e);
+        }
+
+        return null;
+    }
 }
 
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
new file mode 100644
index 0000000..f1f683c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -0,0 +1,467 @@
+/*
+ * 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.ims;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.CarrierConfigManager;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MMTelFeature;
+import android.telephony.ims.feature.RcsFeature;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsUt;
+import com.android.internal.annotations.VisibleForTesting;
+
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+
+/**
+ * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
+ * ImsService must register the service in their AndroidManifest to be detected by the framework.
+ * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE"
+ * permission. Then, the ImsService definition in the manifest must follow the following format:
+ *
+ * ...
+ * <service android:name=".EgImsService"
+ *     android:permission="android.permission.BIND_IMS_SERVICE" >
+ *     <!-- Apps must declare which features they support as metadata. The different categories are
+ *     defined below. In this example, the RCS_FEATURE feature is supported. -->
+ *     <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" />
+ *     <intent-filter>
+ *         <action android:name="android.telephony.ims.ImsService" />
+ *     </intent-filter>
+ * </service>
+ * ...
+ *
+ * The telephony framework will then bind to the ImsService you have defined in your manifest
+ * if you are either:
+ * 1) Defined as the default ImsService for the device in the device overlay using
+ *    "config_ims_package".
+ * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
+ *    {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
+ *
+ * The features that are currently supported in an ImsService are:
+ * - RCS_FEATURE: This ImsService implements the {@link RcsFeature} class.
+ * - MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class.
+ * - EMERGENCY_MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class and will be
+ *   available to place emergency calls at all times. This MUST be implemented by the default
+ *   ImsService provided in the device overlay.
+ *
+ * @hide
+ */
+public abstract class ImsService extends ImsServiceBase {
+
+    private static final String LOG_TAG = "ImsService";
+
+    /**
+     * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
+     */
+    public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
+
+    // A map of slot Id -> Set of features corresponding to that slot.
+    private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>();
+
+    // Implements all supported features as a flat interface.
+    protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
+
+        @Override
+        public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+                throws RemoteException {
+            synchronized (mFeatures) {
+                enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature");
+                onCreateImsFeatureInternal(slotId, feature, c);
+            }
+        }
+
+        @Override
+        public void removeImsFeature(int slotId, int feature) throws RemoteException {
+            synchronized (mFeatures) {
+                enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature");
+                onRemoveImsFeatureInternal(slotId, feature);
+            }
+        }
+
+        @Override
+        public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
+                IImsRegistrationListener listener) throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.startSession(incomingCallIntent, listener);
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
+            synchronized (mFeatures) {
+                enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession");
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.endSession(sessionId);
+                }
+            }
+        }
+
+        @Override
+        public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
+                throws RemoteException {
+            enforceReadPhoneStatePermission("isConnected");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.isConnected(callSessionType, callType);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean isOpened(int slotId, int featureType) throws RemoteException {
+            enforceReadPhoneStatePermission("isOpened");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.isOpened();
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
+            enforceReadPhoneStatePermission("getFeatureStatus");
+            int status = ImsFeature.STATE_NOT_AVAILABLE;
+            synchronized (mFeatures) {
+                SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+                if (featureMap != null) {
+                    ImsFeature feature = getImsFeatureFromType(featureMap, featureType);
+                    if (feature != null) {
+                        status = feature.getFeatureState();
+                    }
+                }
+            }
+            return status;
+        }
+
+        @Override
+        public void addRegistrationListener(int slotId, int featureType,
+                IImsRegistrationListener listener) throws RemoteException {
+            enforceReadPhoneStatePermission("addRegistrationListener");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.addRegistrationListener(listener);
+                }
+            }
+        }
+
+        @Override
+        public void removeRegistrationListener(int slotId, int featureType,
+                IImsRegistrationListener listener) throws RemoteException {
+            enforceReadPhoneStatePermission("removeRegistrationListener");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.removeRegistrationListener(listener);
+                }
+            }
+        }
+
+        @Override
+        public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
+                int callSessionType, int callType) throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.createCallProfile(sessionId, callSessionType,  callType);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
+                ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.createCallSession(sessionId, profile, listener);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
+                String callId) throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.getPendingCallSession(sessionId, callId);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public IImsUt getUtInterface(int slotId, int featureType)
+                throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.getUtInterface();
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public IImsConfig getConfigInterface(int slotId, int featureType)
+                throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.getConfigInterface();
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void turnOnIms(int slotId, int featureType) throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.turnOnIms();
+                }
+            }
+        }
+
+        @Override
+        public void turnOffIms(int slotId, int featureType) throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.turnOffIms();
+                }
+            }
+        }
+
+        @Override
+        public IImsEcbm getEcbmInterface(int slotId, int featureType)
+                throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.getEcbmInterface();
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete)
+                throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.setUiTTYMode(uiTtyMode, onComplete);
+                }
+            }
+        }
+
+        @Override
+        public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
+                throws RemoteException {
+            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface");
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    return feature.getMultiEndpointInterface();
+                }
+            }
+            return null;
+        }
+
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if(SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mImsServiceController;
+        }
+        return null;
+    }
+
+    /**
+     * Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and
+     * featureType
+     * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
+     * @param featureType An integer representing the type of ImsFeature being created. This is
+     * defined in {@link ImsFeature}.
+     */
+    // Be sure to lock on mFeatures before accessing this method
+    private void onCreateImsFeatureInternal(int slotId, int featureType,
+            IImsFeatureStatusCallback c) {
+        SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+        if (featureMap == null) {
+            featureMap = new SparseArray<>();
+            mFeatures.put(slotId, featureMap);
+        }
+        ImsFeature f = makeImsFeature(slotId, featureType);
+        if (f != null) {
+            f.setContext(this);
+            f.setSlotId(slotId);
+            f.setImsFeatureStatusCallback(c);
+            featureMap.put(featureType, f);
+        }
+
+    }
+    /**
+     * Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and
+     * featureType.
+     * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
+     * @param featureType An integer representing the type of ImsFeature being removed. This is
+     * defined in {@link ImsFeature}.
+     */
+    // Be sure to lock on mFeatures before accessing this method
+    private void onRemoveImsFeatureInternal(int slotId, int featureType) {
+        SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+        if (featureMap == null) {
+            return;
+        }
+
+        ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType);
+        if (featureToRemove != null) {
+            featureMap.remove(featureType);
+            featureToRemove.notifyFeatureRemoved(slotId);
+            // Remove reference to Binder
+            featureToRemove.setImsFeatureStatusCallback(null);
+        }
+    }
+
+    // Be sure to lock on mFeatures before accessing this method
+    private MMTelFeature resolveMMTelFeature(int slotId, int featureType) {
+        SparseArray<ImsFeature> features = getImsFeatureMap(slotId);
+        MMTelFeature feature = null;
+        if (features != null) {
+            feature = resolveImsFeature(features, featureType, MMTelFeature.class);
+        }
+        return feature;
+    }
+
+    // Be sure to lock on mFeatures before accessing this method
+    private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType,
+            Class<T> className) {
+        ImsFeature feature = getImsFeatureFromType(set, featureType);
+        if (feature == null) {
+            return null;
+        }
+        try {
+            return className.cast(feature);
+        } catch (ClassCastException e)
+        {
+            Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage());
+        }
+        return null;
+    }
+
+    @VisibleForTesting
+    // Be sure to lock on mFeatures before accessing this method
+    public SparseArray<ImsFeature> getImsFeatureMap(int slotId) {
+        return mFeatures.get(slotId);
+    }
+
+    @VisibleForTesting
+    // Be sure to lock on mFeatures before accessing this method
+    public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) {
+        return set.get(featureType);
+    }
+
+    private ImsFeature makeImsFeature(int slotId, int feature) {
+        switch (feature) {
+            case ImsFeature.EMERGENCY_MMTEL: {
+                return onCreateEmergencyMMTelImsFeature(slotId);
+            }
+            case ImsFeature.MMTEL: {
+                return onCreateMMTelImsFeature(slotId);
+            }
+            case ImsFeature.RCS: {
+                return onCreateRcsFeature(slotId);
+            }
+        }
+        // Tried to create feature that is not defined.
+        return null;
+    }
+
+    /**
+     * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
+     * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
+     */
+    private void enforceReadPhoneStatePermission(String fn) {
+        if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+                != PackageManager.PERMISSION_GRANTED) {
+            enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+        }
+    }
+
+    /**
+     * @return An implementation of MMTelFeature that will be used by the system for MMTel
+     * functionality. Must be able to handle emergency calls at any time as well.
+     */
+    public abstract MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId);
+
+    /**
+     * @return An implementation of MMTelFeature that will be used by the system for MMTel
+     * functionality.
+     */
+    public abstract MMTelFeature onCreateMMTelImsFeature(int slotId);
+
+    /**
+     * @return An implementation of RcsFeature that will be used by the system for RCS.
+     */
+    public abstract RcsFeature onCreateRcsFeature(int slotId);
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceBase.java b/telephony/java/android/telephony/ims/ImsServiceBase.java
index 0b50eca..0878db8 100644
--- a/telephony/java/android/telephony/ims/ImsServiceBase.java
+++ b/telephony/java/android/telephony/ims/ImsServiceBase.java
@@ -22,7 +22,9 @@
 import android.os.IBinder;
 
 /**
- * Base ImsService Implementation, which is used by the ImsResolver to bind.
+ * Base ImsService Implementation, which is used by the ImsResolver to bind. ImsServices that do not
+ * need to provide an ImsService implementation but still wish to be managed by the ImsResolver
+ * lifecycle may implement this class directly.
  * @hide
  */
 @SystemApi
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
new file mode 100644
index 0000000..38ea6e6f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceProxy.java
@@ -0,0 +1,313 @@
+/*
+ * 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.ims;
+
+import android.app.PendingIntent;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.ims.feature.IRcsFeature;
+import android.telephony.ims.feature.ImsFeature;
+import android.util.Log;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
+ * the platform currently supports: MMTel and RCS.
+ * @hide
+ */
+
+public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
+
+    protected String LOG_TAG = "ImsServiceProxy";
+    private final int mSupportedFeature;
+
+    // Start by assuming the proxy is available for usage.
+    private boolean mIsAvailable = true;
+    // ImsFeature Status from the ImsService. Cached.
+    private Integer mFeatureStatusCached = null;
+    private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
+    private final Object mLock = new Object();
+
+    public interface INotifyStatusChanged {
+        void notifyStatusChanged();
+    }
+
+    private final IImsServiceFeatureListener mListenerBinder =
+            new IImsServiceFeatureListener.Stub() {
+
+        @Override
+        public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
+            // The feature has been re-enabled. This may happen when the service crashes.
+            synchronized (mLock) {
+                if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
+                    Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
+                            feature);
+                    mIsAvailable = true;
+                }
+            }
+        }
+
+        @Override
+        public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
+            synchronized (mLock) {
+                if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
+                    Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
+                            feature);
+                    mIsAvailable = false;
+                }
+            }
+        }
+
+        @Override
+        public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
+            synchronized (mLock) {
+                Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
+                        " status: " + status);
+                if (mSlotId == slotId && feature == mSupportedFeature) {
+                    mFeatureStatusCached = status;
+                }
+            }
+            if (mStatusCallback != null) {
+                mStatusCallback.notifyStatusChanged();
+            }
+        }
+    };
+
+    public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
+        super(slotId, binder);
+        mSupportedFeature = featureType;
+    }
+
+    public ImsServiceProxy(int slotId, int featureType) {
+        super(slotId, null /*IBinder*/);
+        mSupportedFeature = featureType;
+    }
+
+    public IImsServiceFeatureListener getListener() {
+        return mListenerBinder;
+    }
+
+    public void setBinder(IBinder binder) {
+        mBinder = binder;
+    }
+
+    @Override
+    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+            throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
+                    incomingCallIntent, listener);
+        }
+    }
+
+    @Override
+    public void endSession(int sessionId) throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
+        }
+    }
+
+    @Override
+    public boolean isConnected(int callServiceType, int callType)
+            throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
+                    callServiceType, callType);
+        }
+    }
+
+    @Override
+    public boolean isOpened() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
+        }
+    }
+
+    @Override
+    public void addRegistrationListener(IImsRegistrationListener listener)
+    throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
+                    listener);
+        }
+    }
+
+    @Override
+    public void removeRegistrationListener(IImsRegistrationListener listener)
+            throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
+                    listener);
+        }
+    }
+
+    @Override
+    public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+            throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
+                    sessionId, callServiceType, callType);
+        }
+    }
+
+    @Override
+    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+            IImsCallSessionListener listener) throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
+                    sessionId, profile, listener);
+        }
+    }
+
+    @Override
+    public IImsCallSession getPendingCallSession(int sessionId, String callId)
+            throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
+                    sessionId, callId);
+        }
+    }
+
+    @Override
+    public IImsUt getUtInterface() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
+        }
+    }
+
+    @Override
+    public IImsConfig getConfigInterface() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
+        }
+    }
+
+    @Override
+    public void turnOnIms() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
+        }
+    }
+
+    @Override
+    public void turnOffIms() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
+        }
+    }
+
+    @Override
+    public IImsEcbm getEcbmInterface() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
+        }
+    }
+
+    @Override
+    public void setUiTTYMode(int uiTtyMode, Message onComplete)
+            throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
+                    onComplete);
+        }
+    }
+
+    @Override
+    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+        synchronized (mLock) {
+            checkBinderConnection();
+            return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
+                    mSupportedFeature);
+        }
+    }
+
+    @Override
+    public int getFeatureStatus() {
+        synchronized (mLock) {
+            if (mFeatureStatusCached != null) {
+                return mFeatureStatusCached;
+            }
+        }
+        // Don't synchronize on Binder call.
+        Integer status = retrieveFeatureStatus();
+        synchronized (mLock) {
+            if (status == null) {
+                return ImsFeature.STATE_NOT_AVAILABLE;
+            }
+            // Cache only non-null value for feature status.
+            mFeatureStatusCached = status;
+        }
+        return status;
+    }
+
+    /**
+     * Internal method used to retrieve the feature status from the corresponding ImsService.
+     */
+    private Integer retrieveFeatureStatus() {
+        if (mBinder != null) {
+            try {
+                return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
+            } catch (RemoteException e) {
+                // Status check failed, don't update cache
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param c Callback that will fire when the feature status has changed.
+     */
+    public void setStatusCallback(INotifyStatusChanged c) {
+        mStatusCallback = c;
+    }
+
+    @Override
+    public boolean isBinderAlive() {
+        return mIsAvailable && getFeatureStatus() == ImsFeature.STATE_READY && mBinder != null &&
+                mBinder.isBinderAlive();
+    }
+
+    private IImsServiceController getServiceInterface(IBinder b) {
+        return IImsServiceController.Stub.asInterface(b);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
new file mode 100644
index 0000000..bbd5f02
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
@@ -0,0 +1,183 @@
+/*
+ * 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.ims;
+
+import android.app.PendingIntent;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.ims.feature.IMMTelFeature;
+import android.telephony.ims.feature.ImsFeature;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsService;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * Compatibility class that implements the new ImsService IMMTelFeature interface, but
+ * uses the old IImsService interface to support older devices that implement the deprecated
+ * opt/net/ims interface.
+ * @hide
+ */
+
+public class ImsServiceProxyCompat implements IMMTelFeature {
+
+    private static final int SERVICE_ID = ImsFeature.MMTEL;
+
+    protected final int mSlotId;
+    protected IBinder mBinder;
+
+    public ImsServiceProxyCompat(int slotId, IBinder binder) {
+        mSlotId = slotId;
+        mBinder = binder;
+    }
+
+    @Override
+    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+            throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
+                listener);
+    }
+
+    @Override
+    public void endSession(int sessionId) throws RemoteException {
+        checkBinderConnection();
+        getServiceInterface(mBinder).close(sessionId);
+    }
+
+    @Override
+    public boolean isConnected(int callServiceType, int callType)
+            throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).isConnected(SERVICE_ID,  callServiceType, callType);
+    }
+
+    @Override
+    public boolean isOpened() throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).isOpened(SERVICE_ID);
+    }
+
+    @Override
+    public void addRegistrationListener(IImsRegistrationListener listener)
+            throws RemoteException {
+        checkBinderConnection();
+        getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
+    }
+
+    @Override
+    public void removeRegistrationListener(IImsRegistrationListener listener)
+            throws RemoteException {
+        // Not Implemented in old ImsService. If the registration listener becomes invalid, the
+        // ImsService will remove.
+    }
+
+    @Override
+    public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+            throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
+    }
+
+    @Override
+    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+            IImsCallSessionListener listener) throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
+    }
+
+    @Override
+    public IImsCallSession getPendingCallSession(int sessionId, String callId)
+            throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
+    }
+
+    @Override
+    public IImsUt getUtInterface() throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).getUtInterface(SERVICE_ID);
+    }
+
+    @Override
+    public IImsConfig getConfigInterface() throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).getConfigInterface(mSlotId);
+    }
+
+    @Override
+    public void turnOnIms() throws RemoteException {
+        checkBinderConnection();
+        getServiceInterface(mBinder).turnOnIms(mSlotId);
+    }
+
+    @Override
+    public void turnOffIms() throws RemoteException {
+        checkBinderConnection();
+        getServiceInterface(mBinder).turnOffIms(mSlotId);
+    }
+
+    @Override
+    public IImsEcbm getEcbmInterface() throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).getEcbmInterface(SERVICE_ID);
+    }
+
+    @Override
+    public void setUiTTYMode(int uiTtyMode, Message onComplete)
+            throws RemoteException {
+        checkBinderConnection();
+        getServiceInterface(mBinder).setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
+    }
+
+    @Override
+    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+        checkBinderConnection();
+        return getServiceInterface(mBinder).getMultiEndpointInterface(SERVICE_ID);
+    }
+
+    /**
+     * Base implementation, always returns READY for compatibility with old ImsService.
+     */
+    public int getFeatureStatus() {
+        return ImsFeature.STATE_READY;
+    }
+
+    /**
+     * @return false if the binder connection is no longer alive.
+     */
+    public boolean isBinderAlive() {
+        return mBinder != null && mBinder.isBinderAlive();
+    }
+
+    private IImsService getServiceInterface(IBinder b) {
+        return IImsService.Stub.asInterface(b);
+    }
+
+    protected void checkBinderConnection() throws RemoteException {
+        if (!isBinderAlive()) {
+            throw new RemoteException("ImsServiceProxy is not available for that feature.");
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
new file mode 100644
index 0000000..d65e27e
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
@@ -0,0 +1,187 @@
+/*
+ * 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.ims.feature;
+
+import android.app.PendingIntent;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * MMTel interface for an ImsService. When updating this interface, ensure that base implementations
+ * of your changes are also present in MMTelFeature for compatibility with older versions of the
+ * MMTel feature.
+ * @hide
+ */
+
+public interface IMMTelFeature {
+
+    /**
+     * Notifies the MMTel feature that you would like to start a session. This should always be
+     * done before making/receiving IMS calls. The IMS service will register the device to the
+     * operator's network with the credentials (from ISIM) periodically in order to receive calls
+     * from the operator's network. When the IMS service receives a new call, it will send out an
+     * intent with the provided action string. The intent contains a call ID extra
+     * {@link IImsCallSession#getCallId} and it can be used to take a call.
+     *
+     * @param incomingCallIntent When an incoming call is received, the IMS service will call
+     * {@link PendingIntent#send} to send back the intent to the caller with
+     * {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
+     * It cannot be null.
+     * @param listener To listen to IMS registration events; It cannot be null
+     * @return an integer (greater than 0) representing the session id associated with the session
+     * that has been started.
+     */
+    int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+            throws RemoteException;
+
+    /**
+     * End a previously started session using the associated sessionId.
+     * @param sessionId an integer (greater than 0) representing the ongoing session. See
+     * {@link #startSession}.
+     */
+    void endSession(int sessionId) throws RemoteException;
+
+    /**
+     * Checks if the IMS service has successfully registered to the IMS network with the specified
+     * service & call type.
+     *
+     * @param callServiceType a service type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+     *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+     * @param callType a call type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
+     *        {@link ImsCallProfile#CALL_TYPE_VOICE}
+     *        {@link ImsCallProfile#CALL_TYPE_VT}
+     *        {@link ImsCallProfile#CALL_TYPE_VS}
+     * @return true if the specified service id is connected to the IMS network; false otherwise
+     * @throws RemoteException
+     */
+    boolean isConnected(int callServiceType, int callType) throws RemoteException;
+
+    /**
+     * Checks if the specified IMS service is opened.
+     *
+     * @return true if the specified service id is opened; false otherwise
+     */
+    boolean isOpened() throws RemoteException;
+
+    /**
+     * Add a new registration listener for the client associated with the session Id.
+     * @param listener An implementation of IImsRegistrationListener.
+     */
+    void addRegistrationListener(IImsRegistrationListener listener)
+            throws RemoteException;
+
+    /**
+     * Remove a previously registered listener using {@link #addRegistrationListener} for the client
+     * associated with the session Id.
+     * @param listener A previously registered IImsRegistrationListener
+     */
+    void removeRegistrationListener(IImsRegistrationListener listener)
+            throws RemoteException;
+
+    /**
+     * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
+     *
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     * @param callServiceType a service type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#SERVICE_TYPE_NONE}
+     *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+     *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+     * @param callType a call type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#CALL_TYPE_VOICE}
+     *        {@link ImsCallProfile#CALL_TYPE_VT}
+     *        {@link ImsCallProfile#CALL_TYPE_VT_TX}
+     *        {@link ImsCallProfile#CALL_TYPE_VT_RX}
+     *        {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
+     *        {@link ImsCallProfile#CALL_TYPE_VS}
+     *        {@link ImsCallProfile#CALL_TYPE_VS_TX}
+     *        {@link ImsCallProfile#CALL_TYPE_VS_RX}
+     * @return a {@link ImsCallProfile} object
+     */
+    ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+            throws RemoteException;
+
+    /**
+     * Creates a {@link ImsCallSession} with the specified call profile.
+     * Use other methods, if applicable, instead of interacting with
+     * {@link ImsCallSession} directly.
+     *
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     * @param profile a call profile to make the call
+     * @param listener An implementation of IImsCallSessionListener.
+     */
+    IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+            IImsCallSessionListener listener) throws RemoteException;
+
+    /**
+     * Retrieves the call session associated with a pending call.
+     *
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     * @param callId a call id to make the call
+     */
+    IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
+
+    /**
+     * @return The Ut interface for the supplementary service configuration.
+     */
+    IImsUt getUtInterface() throws RemoteException;
+
+    /**
+     * @return The config interface for IMS Configuration
+     */
+    IImsConfig getConfigInterface() throws RemoteException;
+
+    /**
+     * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     */
+    void turnOnIms() throws RemoteException;
+
+    /**
+     * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     */
+    void turnOffIms() throws RemoteException;
+
+    /**
+     * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
+     */
+    IImsEcbm getEcbmInterface() throws RemoteException;
+
+    /**
+     * Sets the current UI TTY mode for the MMTelFeature.
+     * @param uiTtyMode An integer containing the new UI TTY Mode.
+     * @param onComplete A {@link Message} to be used when the mode has been set.
+     * @throws RemoteException
+     */
+    void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException;
+
+    /**
+     * @return MultiEndpoint interface for DEP notifications
+     */
+    IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException;
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
new file mode 100644
index 0000000..e28e1b3
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
@@ -0,0 +1,26 @@
+/*
+ * 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.ims.feature;
+
+/**
+ * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
+ * in the framework.
+ * @hide
+ */
+
+public interface IRcsFeature {
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 0509d60..988dd58 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -16,18 +16,175 @@
 
 package android.telephony.ims.feature;
 
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.ims.internal.IImsFeatureStatusCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Base class for all IMS features that are supported by the framework.
  * @hide
  */
-public class ImsFeature {
+public abstract class ImsFeature {
+
+    private static final String LOG_TAG = "ImsFeature";
+
+    /**
+     * Action to broadcast when ImsService is up.
+     * Internal use only.
+     * Only defined here separately compatibility purposes with the old ImsService.
+     * @hide
+     */
+    public static final String ACTION_IMS_SERVICE_UP =
+            "com.android.ims.IMS_SERVICE_UP";
+
+    /**
+     * Action to broadcast when ImsService is down.
+     * Internal use only.
+     * Only defined here separately for compatibility purposes with the old ImsService.
+     * @hide
+     */
+    public static final String ACTION_IMS_SERVICE_DOWN =
+            "com.android.ims.IMS_SERVICE_DOWN";
+
+    /**
+     * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
+     * A long value; the phone ID corresponding to the IMS service coming up or down.
+     * Only defined here separately for compatibility purposes with the old ImsService.
+     * @hide
+     */
+    public static final String EXTRA_PHONE_ID = "android:phone_id";
 
     // Invalid feature value
     public static final int INVALID = -1;
-    // ImsFeatures that are defined in the Manifests
+    // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
+    // defined values in ImsServiceClass for compatibility purposes.
     public static final int EMERGENCY_MMTEL = 0;
     public static final int MMTEL = 1;
     public static final int RCS = 2;
     // Total number of features defined
     public static final int MAX = 3;
+
+    // Integer values defining the state of the ImsFeature at any time.
+    @IntDef(flag = true,
+            value = {
+                    STATE_NOT_AVAILABLE,
+                    STATE_INITIALIZING,
+                    STATE_READY,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsState {}
+    public static final int STATE_NOT_AVAILABLE = 0;
+    public static final int STATE_INITIALIZING = 1;
+    public static final int STATE_READY = 2;
+
+    private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
+    private IImsFeatureStatusCallback mStatusCallback;
+    private @ImsState int mState = STATE_NOT_AVAILABLE;
+    private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+    private Context mContext;
+
+    public interface INotifyFeatureRemoved {
+        void onFeatureRemoved(int slotId);
+    }
+
+    public void setContext(Context context) {
+        mContext = context;
+    }
+
+    public void setSlotId(int slotId) {
+        mSlotId = slotId;
+    }
+
+    public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
+        synchronized (mRemovedListeners) {
+            mRemovedListeners.add(listener);
+        }
+    }
+
+    public void removeFeatureRemovedListener(INotifyFeatureRemoved listener) {
+        synchronized (mRemovedListeners) {
+            mRemovedListeners.remove(listener);
+        }
+    }
+
+    // Not final for testing.
+    public void notifyFeatureRemoved(int slotId) {
+        synchronized (mRemovedListeners) {
+            mRemovedListeners.forEach(l -> l.onFeatureRemoved(slotId));
+            onFeatureRemoved();
+        }
+    }
+
+    public int getFeatureState() {
+        return mState;
+    }
+
+    protected final void setFeatureState(@ImsState int state) {
+        if (mState != state) {
+            mState = state;
+            notifyFeatureState(state);
+        }
+    }
+
+    // Not final for testing.
+    public void setImsFeatureStatusCallback(IImsFeatureStatusCallback c) {
+        mStatusCallback = c;
+        // If we have just connected, send queued status.
+        notifyFeatureState(mState);
+    }
+
+    /**
+     * Internal method called by ImsFeature when setFeatureState has changed.
+     * @param state
+     */
+    private void notifyFeatureState(@ImsState int state) {
+        if (mStatusCallback != null) {
+            try {
+                Log.i(LOG_TAG, "notifying ImsFeatureState");
+                mStatusCallback.notifyImsFeatureStatus(state);
+            } catch (RemoteException e) {
+                mStatusCallback = null;
+                Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
+            }
+        }
+        sendImsServiceIntent(state);
+    }
+
+    /**
+     * Provide backwards compatibility using deprecated service UP/DOWN intents.
+     */
+    private void sendImsServiceIntent(@ImsState int state) {
+        if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+            return;
+        }
+        Intent intent;
+        switch (state) {
+            case ImsFeature.STATE_NOT_AVAILABLE:
+            case ImsFeature.STATE_INITIALIZING:
+                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+                break;
+            case ImsFeature.STATE_READY:
+                intent = new Intent(ACTION_IMS_SERVICE_UP);
+                break;
+            default:
+                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+        }
+        intent.putExtra(EXTRA_PHONE_ID, mSlotId);
+        mContext.sendBroadcast(intent);
+    }
+
+    /**
+     * Called when the feature is being removed and must be cleaned up.
+     */
+    public abstract void onFeatureRemoved();
 }
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
new file mode 100644
index 0000000..a71f0bf
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -0,0 +1,122 @@
+/*
+ * 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.ims.feature;
+
+import android.app.PendingIntent;
+import android.os.Message;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
+ * MMTelFeature should extend this class and implement all methods that the service supports.
+ *
+ * @hide
+ */
+
+public class MMTelFeature extends ImsFeature implements IMMTelFeature {
+
+    @Override
+    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
+        return 0;
+    }
+
+    @Override
+    public void endSession(int sessionId) {
+    }
+
+    @Override
+    public boolean isConnected(int callSessionType, int callType) {
+        return false;
+    }
+
+    @Override
+    public boolean isOpened() {
+        return false;
+    }
+
+    @Override
+    public void addRegistrationListener(IImsRegistrationListener listener) {
+    }
+
+    @Override
+    public void removeRegistrationListener(IImsRegistrationListener listener) {
+    }
+
+    @Override
+    public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
+        return null;
+    }
+
+    @Override
+    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+            IImsCallSessionListener listener) {
+        return null;
+    }
+
+    @Override
+    public IImsCallSession getPendingCallSession(int sessionId, String callId) {
+        return null;
+    }
+
+    @Override
+    public IImsUt getUtInterface() {
+        return null;
+    }
+
+    @Override
+    public IImsConfig getConfigInterface() {
+        return null;
+    }
+
+    @Override
+    public void turnOnIms() {
+    }
+
+    @Override
+    public void turnOffIms() {
+    }
+
+    @Override
+    public IImsEcbm getEcbmInterface() {
+        return null;
+    }
+
+    @Override
+    public void setUiTTYMode(int uiTtyMode, Message onComplete) {
+    }
+
+    @Override
+    public IImsMultiEndpoint getMultiEndpointInterface() {
+        return null;
+    }
+
+    @Override
+    public void onFeatureRemoved() {
+
+    }
+}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
new file mode 100644
index 0000000..9cddc1b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -0,0 +1,35 @@
+/*
+ * 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.ims.feature;
+
+/**
+ * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
+ * this class and provide implementations of the IRcsFeature methods that they support.
+ * @hide
+ */
+
+public class RcsFeature extends ImsFeature implements IRcsFeature {
+
+    public RcsFeature() {
+        super();
+    }
+
+    @Override
+    public void onFeatureRemoved() {
+
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
new file mode 100644
index 0000000..69b8acc
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -0,0 +1,348 @@
+/*
+ * 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.ims.stub;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.internal.ImsCallSession;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsVideoCallProvider;
+
+/**
+ * Base implementation of IImsCallSession, which implements stub versions of the methods in the
+ * IImsCallSession AIDL. Override the methods that your implementation of ImsCallSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsCallSessionImplBase extends IImsCallSession.Stub {
+
+    /**
+     * Closes the object. This object is not usable after being closed.
+     */
+    @Override
+    public void close() throws RemoteException {
+
+    }
+
+    /**
+     * Gets the call ID of the session.
+     *
+     * @return the call ID
+     */
+    @Override
+    public String getCallId() throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Gets the call profile that this session is associated with
+     *
+     * @return the {@link ImsCallProfile} that this session is associated with
+     */
+    @Override
+    public ImsCallProfile getCallProfile() throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Gets the local call profile that this session is associated with
+     *
+     * @return the local {@link ImsCallProfile} that this session is associated with
+     */
+    @Override
+    public ImsCallProfile getLocalCallProfile() throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Gets the remote call profile that this session is associated with
+     *
+     * @return the remote {@link ImsCallProfile} that this session is associated with
+     */
+    @Override
+    public ImsCallProfile getRemoteCallProfile() throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Gets the value associated with the specified property of this session.
+     *
+     * @return the string value associated with the specified property
+     */
+    @Override
+    public String getProperty(String name) throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Gets the session state.
+     * The value returned must be one of the states in {@link ImsCallSession.State}.
+     *
+     * @return the session state
+     */
+    @Override
+    public int getState() throws RemoteException {
+        return ImsCallSession.State.INVALID;
+    }
+
+    /**
+     * Checks if the session is in call.
+     *
+     * @return true if the session is in call, false otherwise
+     */
+    @Override
+    public boolean isInCall() throws RemoteException {
+        return false;
+    }
+
+    /**
+     * Sets the listener to listen to the session events. An {@link ImsCallSession}
+     * can only hold one listener at a time. Subsequent calls to this method
+     * override the previous listener.
+     *
+     * @param listener to listen to the session events of this object
+     */
+    @Override
+    public void setListener(IImsCallSessionListener listener) throws RemoteException {
+    }
+
+    /**
+     * Mutes or unmutes the mic for the active call.
+     *
+     * @param muted true if the call is muted, false otherwise
+     */
+    @Override
+    public void setMute(boolean muted) throws RemoteException {
+    }
+
+    /**
+     * Initiates an IMS call with the specified target and call profile.
+     * The session listener set in {@link #setListener} is called back upon defined session events.
+     * The method is only valid to call when the session state is in
+     * {@link ImsCallSession.State#IDLE}.
+     *
+     * @param callee dialed string to make the call to
+     * @param profile call profile to make the call with the specified service type,
+     *      call type and media information
+     * @see {@link ImsCallSession.Listener#callSessionStarted},
+     * {@link ImsCallSession.Listener#callSessionStartFailed}
+     */
+    @Override
+    public void start(String callee, ImsCallProfile profile) throws RemoteException {
+    }
+
+    /**
+     * Initiates an IMS call with the specified participants and call profile.
+     * The session listener set in {@link #setListener} is called back upon defined session events.
+     * The method is only valid to call when the session state is in
+     * {@link ImsCallSession.State#IDLE}.
+     *
+     * @param participants participant list to initiate an IMS conference call
+     * @param profile call profile to make the call with the specified service type,
+     *      call type and media information
+     * @see {@link ImsCallSession.Listener#callSessionStarted},
+     * {@link ImsCallSession.Listener#callSessionStartFailed}
+     */
+    @Override
+    public void startConference(String[] participants, ImsCallProfile profile)
+            throws RemoteException {
+    }
+
+    /**
+     * Accepts an incoming call or session update.
+     *
+     * @param callType call type specified in {@link ImsCallProfile} to be answered
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+     * @see {@link ImsCallSession.Listener#callSessionStarted}
+     */
+    @Override
+    public void accept(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+    }
+
+    /**
+     * Rejects an incoming call or session update.
+     *
+     * @param reason reason code to reject an incoming call, defined in
+     *         com.android.ims.ImsReasonInfo
+     * {@link ImsCallSession.Listener#callSessionStartFailed}
+     */
+    @Override
+    public void reject(int reason) throws RemoteException {
+    }
+
+    /**
+     * Terminates a call.
+     *
+     * @param reason reason code to terminate a call, defined in
+     *         com.android.ims.ImsReasonInfo
+     *
+     * @see {@link ImsCallSession.Listener#callSessionTerminated}
+     */
+    @Override
+    public void terminate(int reason) throws RemoteException {
+    }
+
+    /**
+     * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is
+     * called.
+     *
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+     * @see {@link ImsCallSession.Listener#callSessionHeld},
+     * {@link ImsCallSession.Listener#callSessionHoldFailed}
+     */
+    @Override
+    public void hold(ImsStreamMediaProfile profile) throws RemoteException {
+    }
+
+    /**
+     * Continues a call that's on hold. When it succeeds,
+     * {@link ImsCallSession.Listener#callSessionResumed} is called.
+     *
+     * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call
+     * @see {@link ImsCallSession.Listener#callSessionResumed},
+     * {@link ImsCallSession.Listener#callSessionResumeFailed}
+     */
+    @Override
+    public void resume(ImsStreamMediaProfile profile) throws RemoteException {
+    }
+
+    /**
+     * Merges the active & hold call. When the merge starts,
+     * {@link ImsCallSession.Listener#callSessionMergeStarted} is called.
+     * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is
+     * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge
+     * fails.
+     *
+     * @see {@link ImsCallSession.Listener#callSessionMergeStarted},
+     * {@link ImsCallSession.Listener#callSessionMergeComplete},
+     *      {@link ImsCallSession.Listener#callSessionMergeFailed}
+     */
+    @Override
+    public void merge() throws RemoteException {
+    }
+
+    /**
+     * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+     *
+     * @param callType call type specified in {@link ImsCallProfile} to be updated
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+     * @see {@link ImsCallSession.Listener#callSessionUpdated},
+     * {@link ImsCallSession.Listener#callSessionUpdateFailed}
+     */
+    @Override
+    public void update(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+    }
+
+    /**
+     * Extends this call to the conference call with the specified recipients.
+     *
+     * @param participants participant list to be invited to the conference call after extending the
+     * call
+     * @see {@link ImsCallSession.Listener#callSessionConferenceExtended},
+     * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed}
+     */
+    @Override
+    public void extendToConference(String[] participants) throws RemoteException {
+    }
+
+    /**
+     * Requests the conference server to invite an additional participants to the conference.
+     *
+     * @param participants participant list to be invited to the conference call
+     * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered},
+     *      {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed}
+     */
+    @Override
+    public void inviteParticipants(String[] participants) throws RemoteException {
+    }
+
+    /**
+     * Requests the conference server to remove the specified participants from the conference.
+     *
+     * @param participants participant list to be removed from the conference call
+     * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered},
+     *      {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed}
+     */
+    @Override
+    public void removeParticipants(String[] participants) throws RemoteException {
+    }
+
+    /**
+     * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    @Override
+    public void sendDtmf(char c, Message result) throws RemoteException {
+    }
+
+    /**
+     * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    @Override
+    public void startDtmf(char c) throws RemoteException {
+    }
+
+    /**
+     * Stop a DTMF code.
+     */
+    @Override
+    public void stopDtmf() throws RemoteException {
+    }
+
+    /**
+     * Sends an USSD message.
+     *
+     * @param ussdMessage USSD message to send
+     */
+    @Override
+    public void sendUssd(String ussdMessage) throws RemoteException {
+    }
+
+    /**
+     * Returns a binder for the video call provider implementation contained within the IMS service
+     * process. This binder is used by the VideoCallProvider subclass in Telephony which
+     * intermediates between the propriety implementation and Telecomm/InCall.
+     */
+    @Override
+    public IImsVideoCallProvider getVideoCallProvider() throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Determines if the current session is multiparty.
+     * @return {@code True} if the session is multiparty.
+     */
+    @Override
+    public boolean isMultiparty() throws RemoteException {
+        return false;
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
new file mode 100644
index 0000000..46f8f80
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
@@ -0,0 +1,251 @@
+/*
+ * 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.ims.stub;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+
+/**
+ * Base implementation of ImsCallSessionListenerBase, which implements stub versions of the methods
+ * in the IImsCallSessionListener AIDL. Override the methods that your implementation of
+ * ImsCallSessionListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSessionListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+public class ImsCallSessionListenerImplBase extends IImsCallSessionListener.Stub {
+    /**
+     * Notifies the result of the basic session operation (setup / terminate).
+     */
+    @Override
+    public void callSessionProgressing(IImsCallSession session, ImsStreamMediaProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionStarted(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionStartFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionTerminated(IImsCallSession session, ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    /**
+     * Notifies the result of the call hold/resume operation.
+     */
+    @Override
+    public void callSessionHeld(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionHoldFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionHoldReceived(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionResumed(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionResumeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionResumeReceived(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    /**
+     * Notifies the result of call merge operation.
+     */
+    @Override
+    public void callSessionMergeStarted(IImsCallSession session, IImsCallSession newSession,
+            ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionMergeComplete(IImsCallSession session) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionMergeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    /**
+     * Notifies the result of call upgrade / downgrade or any other call
+     * updates.
+     */
+    @Override
+    public void callSessionUpdated(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionUpdateFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionUpdateReceived(IImsCallSession session, ImsCallProfile profile) {
+        // no-op
+    }
+
+    /**
+     * Notifies the result of conference extension.
+     */
+    @Override
+    public void callSessionConferenceExtended(IImsCallSession session, IImsCallSession newSession,
+            ImsCallProfile profile) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionConferenceExtendFailed(IImsCallSession session,
+            ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionConferenceExtendReceived(IImsCallSession session,
+            IImsCallSession newSession,
+            ImsCallProfile profile) {
+        // no-op
+    }
+
+    /**
+     * Notifies the result of the participant invitation / removal to/from the
+     * conference session.
+     */
+    @Override
+    public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+            ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+            ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    /**
+     * Notifies the changes of the conference info. the conference session.
+     */
+    @Override
+    public void callSessionConferenceStateUpdated(IImsCallSession session,
+            ImsConferenceState state) {
+        // no-op
+    }
+
+    /**
+     * Notifies the incoming USSD message.
+     */
+    @Override
+    public void callSessionUssdMessageReceived(IImsCallSession session, int mode,
+            String ussdMessage) {
+        // no-op
+    }
+
+    /**
+     * Notifies of handover information for this call
+     */
+    @Override
+    public void callSessionHandover(IImsCallSession session, int srcAccessTech,
+            int targetAccessTech,
+            ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    @Override
+    public void callSessionHandoverFailed(IImsCallSession session, int srcAccessTech,
+            int targetAccessTech,
+            ImsReasonInfo reasonInfo) {
+        // no-op
+    }
+
+    /**
+     * Notifies the TTY mode change by remote party.
+     *
+     * @param mode one of the following: -
+     *            {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} -
+     *            {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} -
+     *            {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} -
+     *            {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
+     */
+    @Override
+    public void callSessionTtyModeReceived(IImsCallSession session, int mode) {
+        // no-op
+    }
+
+    /**
+     * Notifies of a change to the multiparty state for this
+     * {@code ImsCallSession}.
+     *
+     * @param session The call session.
+     * @param isMultiParty {@code true} if the session became multiparty,
+     *            {@code false} otherwise.
+     */
+    @Override
+    public void callSessionMultipartyStateChanged(IImsCallSession session, boolean isMultiParty) {
+        // no-op
+    }
+
+    /**
+     * Notifies the supplementary service information for the current session.
+     */
+    @Override
+    public void callSessionSuppServiceReceived(IImsCallSession session,
+            ImsSuppServiceNotification suppSrvNotification) {
+        // no-op
+    }
+}
+
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
new file mode 100644
index 0000000..5a4db99
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -0,0 +1,150 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsConfigListener;
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Base implementation of ImsConfig, which implements stub versions of the methods
+ * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsConfig maintained by other ImsServices.
+ *
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+
+public class ImsConfigImplBase extends IImsConfig.Stub {
+
+    /**
+     * Gets the value for ims service/capabilities parameters from the provisioned
+     * value storage. Synchronous blocking call.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @return value in Integer format.
+     */
+    @Override
+    public int getProvisionedValue(int item) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Gets the value for ims service/capabilities parameters from the provisioned
+     * value storage. Synchronous blocking call.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @return value in String format.
+     */
+    @Override
+    public String getProvisionedStringValue(int item) throws RemoteException {
+        return null;
+    }
+
+    /**
+     * Sets the value for IMS service/capabilities parameters by the operator device
+     * management entity. It sets the config item value in the provisioned storage
+     * from which the master value is derived. Synchronous blocking call.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in Integer format.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+     */
+    @Override
+    public int setProvisionedValue(int item, int value) throws RemoteException {
+        return ImsConfig.OperationStatusConstants.FAILED;
+    }
+
+    /**
+     * Sets the value for IMS service/capabilities parameters by the operator device
+     * management entity. It sets the config item value in the provisioned storage
+     * from which the master value is derived.  Synchronous blocking call.
+     *
+     * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in String format.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+     */
+    @Override
+    public int setProvisionedStringValue(int item, String value) throws RemoteException {
+        return ImsConfig.OperationStatusConstants.FAILED;
+    }
+
+    /**
+     * Gets the value of the specified IMS feature item for specified network type.
+     * This operation gets the feature config value from the master storage (i.e. final
+     * value). Asynchronous non-blocking call.
+     *
+     * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+     * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+     * @param listener feature value returned asynchronously through listener.
+     */
+    @Override
+    public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+            throws RemoteException {
+    }
+
+    /**
+     * Sets the value for IMS feature item for specified network type.
+     * This operation stores the user setting in setting db from which master db
+     * is derived.
+     *
+     * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+     * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+     * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
+     * @param listener, provided if caller needs to be notified for set result.
+     */
+    @Override
+    public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+            throws RemoteException {
+    }
+
+    /**
+     * Gets the value for IMS VoLTE provisioned.
+     * This should be the same as the operator provisioned value if applies.
+     */
+    @Override
+    public boolean getVolteProvisioned() throws RemoteException {
+        return false;
+    }
+
+    /**
+     * Gets the value for IMS feature item video quality.
+     *
+     * @param listener Video quality value returned asynchronously through listener.
+     */
+    @Override
+    public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+    }
+
+    /**
+     * Sets the value for IMS feature item video quality.
+     *
+     * @param quality, defines the value of video quality.
+     * @param listener, provided if caller needs to be notified for set result.
+     */
+    @Override
+    public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
new file mode 100644
index 0000000..89f95ff
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -0,0 +1,51 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsEcbmListener;
+
+/**
+ * Base implementation of ImsEcbm, which implements stub versions of the methods
+ * in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsEcbm maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsEcbmImplBase extends IImsEcbm.Stub {
+
+    /**
+     * Sets the listener.
+     */
+    @Override
+    public void setListener(IImsEcbmListener listener) throws RemoteException {
+
+    }
+
+    /**
+     * Requests Modem to come out of ECBM mode
+     */
+    @Override
+    public void exitEmergencyCallbackMode() throws RemoteException {
+
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
new file mode 100644
index 0000000..05da9da
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsExternalCallStateListener;
+import com.android.ims.internal.IImsMultiEndpoint;
+
+/**
+ * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
+ * in the IImsMultiEndpoint AIDL. Override the methods that your implementation of
+ * ImsMultiEndpoint supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsMultiEndpoint maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsMultiEndpointImplBase extends IImsMultiEndpoint.Stub {
+
+    /**
+     * Sets the listener.
+     */
+    @Override
+    public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
+
+    }
+
+    /**
+     * Query API to get the latest Dialog Event Package information
+     * Should be invoked only after setListener is done
+     */
+    @Override
+    public void requestImsExternalCallStateInfo() throws RemoteException {
+
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
new file mode 100644
index 0000000..92f1a01
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsStreamMediaSession;
+
+/**
+ * Base implementation of ImsStreamMediaSession, which implements stub versions of the methods
+ * in the IImsStreamMediaSession AIDL. Override the methods that your implementation of
+ * ImsStreamMediaSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsStreamMediaSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsStreamMediaSessionImplBase extends IImsStreamMediaSession.Stub {
+
+    @Override
+    public void close() throws RemoteException {
+
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
new file mode 100644
index 0000000..dc74094
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -0,0 +1,174 @@
+/*
+ * 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.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUt, which implements stub versions of the methods
+ * in the IImsUt AIDL. Override the methods that your implementation of ImsUt supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUt maintained by other ImsServices.
+ *
+ * Provides the Ut interface interworking to get/set the supplementary service configuration.
+ *
+ * @hide
+ */
+
+public class ImsUtImplBase extends IImsUt.Stub {
+
+    /**
+     * Closes the object. This object is not usable after being closed.
+     */
+    @Override
+    public void close() throws RemoteException {
+
+    }
+
+    /**
+     * Retrieves the configuration of the call barring.
+     */
+    @Override
+    public int queryCallBarring(int cbType) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Retrieves the configuration of the call forward.
+     */
+    @Override
+    public int queryCallForward(int condition, String number) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Retrieves the configuration of the call waiting.
+     */
+    @Override
+    public int queryCallWaiting() throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Retrieves the default CLIR setting.
+     */
+    @Override
+    public int queryCLIR() throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Retrieves the CLIP call setting.
+     */
+    @Override
+    public int queryCLIP() throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Retrieves the COLR call setting.
+     */
+    @Override
+    public int queryCOLR() throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Retrieves the COLP call setting.
+     */
+    @Override
+    public int queryCOLP() throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates or retrieves the supplementary service configuration.
+     */
+    @Override
+    public int transact(Bundle ssInfo) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates the configuration of the call barring.
+     */
+    @Override
+    public int updateCallBarring(int cbType, int action, String[] barrList) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates the configuration of the call forward.
+     */
+    @Override
+    public int updateCallForward(int action, int condition, String number, int serviceClass,
+            int timeSeconds) throws RemoteException {
+        return 0;
+    }
+
+    /**
+     * Updates the configuration of the call waiting.
+     */
+    @Override
+    public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates the configuration of the CLIR supplementary service.
+     */
+    @Override
+    public int updateCLIR(int clirMode) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates the configuration of the CLIP supplementary service.
+     */
+    @Override
+    public int updateCLIP(boolean enable) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates the configuration of the COLR supplementary service.
+     */
+    @Override
+    public int updateCOLR(int presentation) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Updates the configuration of the COLP supplementary service.
+     */
+    @Override
+    public int updateCOLP(boolean enable) throws RemoteException {
+        return -1;
+    }
+
+    /**
+     * Sets the listener.
+     */
+    @Override
+    public void setListener(IImsUtListener listener) throws RemoteException {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
new file mode 100644
index 0000000..b371efb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -0,0 +1,88 @@
+/*
+ * 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.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsInfo;
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUtListener, which implements stub versions of the methods
+ * in the IImsUtListener AIDL. Override the methods that your implementation of
+ * ImsUtListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUtListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsUtListenerImplBase extends IImsUtListener.Stub {
+
+    /**
+     * Notifies the result of the supplementary service configuration udpate.
+     */
+    @Override
+    public void utConfigurationUpdated(IImsUt ut, int id) throws RemoteException {
+    }
+
+    @Override
+    public void utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error)
+            throws RemoteException {
+    }
+
+    /**
+     * Notifies the result of the supplementary service configuration query.
+     */
+    @Override
+    public void utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo) throws RemoteException {
+    }
+
+    @Override
+    public void utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error)
+            throws RemoteException {
+    }
+
+    /**
+     * Notifies the status of the call barring supplementary service.
+     */
+    @Override
+    public void utConfigurationCallBarringQueried(IImsUt ut, int id, ImsSsInfo[] cbInfo)
+            throws RemoteException {
+    }
+
+    /**
+     * Notifies the status of the call forwarding supplementary service.
+     */
+    @Override
+    public void utConfigurationCallForwardQueried(IImsUt ut, int id, ImsCallForwardInfo[] cfInfo)
+            throws RemoteException {
+    }
+
+    /**
+     * Notifies the status of the call waiting supplementary service.
+     */
+    @Override
+    public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
+            throws RemoteException {
+    }
+}
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
new file mode 100644
index 0000000..cd076b1
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -0,0 +1,694 @@
+/*
+ * 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.ims;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.Rlog;
+
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+public class ImsConfig {
+    private static final String TAG = "ImsConfig";
+    private boolean DBG = true;
+    private final IImsConfig miConfig;
+    private Context mContext;
+
+    /**
+     * Broadcast action: the feature enable status was changed
+     *
+     * @hide
+     */
+    public static final String ACTION_IMS_FEATURE_CHANGED =
+            "com.android.intent.action.IMS_FEATURE_CHANGED";
+
+    /**
+     * Broadcast action: the configuration was changed
+     *
+     * @hide
+     */
+    public static final String ACTION_IMS_CONFIG_CHANGED =
+            "com.android.intent.action.IMS_CONFIG_CHANGED";
+
+    /**
+     * Extra parameter "item" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+     * It is the value of FeatureConstants or ConfigConstants.
+     *
+     * @hide
+     */
+    public static final String EXTRA_CHANGED_ITEM = "item";
+
+    /**
+     * Extra parameter "value" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+     * It is the new value of "item".
+     *
+     * @hide
+     */
+    public static final String EXTRA_NEW_VALUE = "value";
+
+    /**
+    * Defines IMS service/capability feature constants.
+    */
+    public static class FeatureConstants {
+        public static final int FEATURE_TYPE_UNKNOWN = -1;
+
+        /**
+         * FEATURE_TYPE_VOLTE supports features defined in 3GPP and
+         * GSMA IR.92 over LTE.
+         */
+        public static final int FEATURE_TYPE_VOICE_OVER_LTE = 0;
+
+        /**
+         * FEATURE_TYPE_LVC supports features defined in 3GPP and
+         * GSMA IR.94 over LTE.
+         */
+        public static final int FEATURE_TYPE_VIDEO_OVER_LTE = 1;
+
+        /**
+         * FEATURE_TYPE_VOICE_OVER_WIFI supports features defined in 3GPP and
+         * GSMA IR.92 over WiFi.
+         */
+        public static final int FEATURE_TYPE_VOICE_OVER_WIFI = 2;
+
+        /**
+         * FEATURE_TYPE_VIDEO_OVER_WIFI supports features defined in 3GPP and
+         * GSMA IR.94 over WiFi.
+         */
+        public static final int FEATURE_TYPE_VIDEO_OVER_WIFI = 3;
+
+        /**
+         * FEATURE_TYPE_UT supports features defined in 3GPP and
+         * GSMA IR.92 over LTE.
+         */
+        public static final int FEATURE_TYPE_UT_OVER_LTE = 4;
+
+       /**
+         * FEATURE_TYPE_UT_OVER_WIFI supports features defined in 3GPP and
+         * GSMA IR.92 over WiFi.
+         */
+        public static final int FEATURE_TYPE_UT_OVER_WIFI = 5;
+    }
+
+    /**
+    * Defines IMS service/capability parameters.
+    */
+    public static class ConfigConstants {
+
+        // Define IMS config items
+        public static final int CONFIG_START = 0;
+
+        // Define operator provisioned config items
+        public static final int PROVISIONED_CONFIG_START = CONFIG_START;
+
+        /**
+         * AMR CODEC Mode Value set, 0-7 in comma separated sequence.
+         * Value is in String format.
+         */
+        public static final int VOCODER_AMRMODESET = CONFIG_START;
+
+        /**
+         * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence.
+         * Value is in String format.
+         */
+        public static final int VOCODER_AMRWBMODESET = 1;
+
+        /**
+         * SIP Session Timer value (seconds).
+         * Value is in Integer format.
+         */
+        public static final int SIP_SESSION_TIMER = 2;
+
+        /**
+         * Minimum SIP Session Expiration Timer in (seconds).
+         * Value is in Integer format.
+         */
+        public static final int MIN_SE = 3;
+
+        /**
+         * SIP_INVITE cancellation time out value (in milliseconds). Integer format.
+         * Value is in Integer format.
+         */
+        public static final int CANCELLATION_TIMER = 4;
+
+        /**
+         * Delay time when an iRAT transition from eHRPD/HRPD/1xRTT to LTE.
+         * Value is in Integer format.
+         */
+        public static final int TDELAY = 5;
+
+        /**
+         * Silent redial status of Enabled (True), or Disabled (False).
+         * Value is in Integer format.
+         */
+        public static final int SILENT_REDIAL_ENABLE = 6;
+
+        /**
+         * SIP T1 timer value in milliseconds. See RFC 3261 for define.
+         * Value is in Integer format.
+         */
+        public static final int SIP_T1_TIMER = 7;
+
+        /**
+         * SIP T2 timer value in milliseconds.  See RFC 3261 for define.
+         * Value is in Integer format.
+         */
+        public static final int SIP_T2_TIMER  = 8;
+
+         /**
+         * SIP TF timer value in milliseconds.  See RFC 3261 for define.
+         * Value is in Integer format.
+         */
+        public static final int SIP_TF_TIMER = 9;
+
+        /**
+         * VoLTE status for VLT/s status of Enabled (1), or Disabled (0).
+         * Value is in Integer format.
+         */
+        public static final int VLT_SETTING_ENABLED = 10;
+
+        /**
+         * VoLTE status for LVC/s status of Enabled (1), or Disabled (0).
+         * Value is in Integer format.
+         */
+        public static final int LVC_SETTING_ENABLED = 11;
+        /**
+         * Domain Name for the device to populate the request URI for REGISTRATION.
+         * Value is in String format.
+         */
+        public static final int DOMAIN_NAME = 12;
+         /**
+         * Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
+         * Value is in Integer format. 3GPP2(0), 3GPP(1)
+         */
+        public static final int SMS_FORMAT = 13;
+         /**
+         * Turns IMS ON/OFF on the device.
+         * Value is in Integer format. ON (1), OFF(0).
+         */
+        public static final int SMS_OVER_IP = 14;
+        /**
+         * Requested expiration for Published Online availability.
+         * Value is in Integer format.
+         */
+        public static final int PUBLISH_TIMER = 15;
+        /**
+         * Requested expiration for Published Offline availability.
+         * Value is in Integer format.
+         */
+        public static final int PUBLISH_TIMER_EXTENDED = 16;
+        /**
+         *
+         * Value is in Integer format.
+         */
+        public static final int CAPABILITY_DISCOVERY_ENABLED = 17;
+        /**
+         * Period of time the capability information of the  contact is cached on handset.
+         * Value is in Integer format.
+         */
+        public static final int CAPABILITIES_CACHE_EXPIRATION = 18;
+        /**
+         * Peiod of time the availability information of a contact is cached on device.
+         * Value is in Integer format.
+         */
+        public static final int AVAILABILITY_CACHE_EXPIRATION = 19;
+        /**
+         * Interval between successive capabilities polling.
+         * Value is in Integer format.
+         */
+        public static final int CAPABILITIES_POLL_INTERVAL = 20;
+        /**
+         * Minimum time between two published messages from the device.
+         * Value is in Integer format.
+         */
+        public static final int SOURCE_THROTTLE_PUBLISH = 21;
+        /**
+         * The Maximum number of MDNs contained in one Request Contained List.
+         * Value is in Integer format.
+         */
+        public static final int MAX_NUMENTRIES_IN_RCL = 22;
+        /**
+         * Expiration timer for subscription of a Request Contained List, used in capability
+         * polling.
+         * Value is in Integer format.
+         */
+        public static final int CAPAB_POLL_LIST_SUB_EXP = 23;
+        /**
+         * Applies compression to LIST Subscription.
+         * Value is in Integer format. Enable (1), Disable(0).
+         */
+        public static final int GZIP_FLAG = 24;
+        /**
+         * VOLTE Status for EAB/s status of Enabled (1), or Disabled (0).
+         * Value is in Integer format.
+         */
+        public static final int EAB_SETTING_ENABLED = 25;
+        /**
+         * Wi-Fi calling roaming status.
+         * Value is in Integer format. ON (1), OFF(0).
+         */
+        public static final int VOICE_OVER_WIFI_ROAMING = 26;
+        /**
+         * Wi-Fi calling modem - WfcModeFeatureValueConstants.
+         * Value is in Integer format.
+         */
+        public static final int VOICE_OVER_WIFI_MODE = 27;
+        /**
+         * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
+         * Value is in Integer format.
+         */
+        public static final int VOICE_OVER_WIFI_SETTING_ENABLED = 28;
+        /**
+         * Mobile data enabled.
+         * Value is in Integer format. On (1), OFF(0).
+         */
+        public static final int MOBILE_DATA_ENABLED = 29;
+        /**
+         * VoLTE user opted in status.
+         * Value is in Integer format. Opted-in (1) Opted-out (0).
+         */
+        public static final int VOLTE_USER_OPT_IN_STATUS = 30;
+        /**
+         * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
+         * Value is in String format.
+         */
+        public static final int LBO_PCSCF_ADDRESS = 31;
+        /**
+         * Keep Alive Enabled for SIP.
+         * Value is in Integer format. On(1), OFF(0).
+         */
+        public static final int KEEP_ALIVE_ENABLED = 32;
+        /**
+         * Registration retry Base Time value in seconds.
+         * Value is in Integer format.
+         */
+        public static final int REGISTRATION_RETRY_BASE_TIME_SEC = 33;
+        /**
+         * Registration retry Max Time value in seconds.
+         * Value is in Integer format.
+         */
+        public static final int REGISTRATION_RETRY_MAX_TIME_SEC = 34;
+        /**
+         * Smallest RTP port for speech codec.
+         * Value is in integer format.
+         */
+        public static final int SPEECH_START_PORT = 35;
+        /**
+         * Largest RTP port for speech code.
+         * Value is in Integer format.
+         */
+        public static final int SPEECH_END_PORT = 36;
+        /**
+         * SIP Timer A's value in milliseconds. Timer A is the INVITE request
+         * retransmit interval, for UDP only.
+         * Value is in Integer format.
+         */
+        public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = 37;
+        /**
+         * SIP Timer B's value in milliseconds. Timer B is the wait time for
+         * INVITE message to be acknowledged.
+         * Value is in Integer format.
+         */
+        public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = 38;
+        /**
+         * SIP Timer D's value in milliseconds. Timer D is the wait time for
+         * response retransmits of the invite client transactions.
+         * Value is in Integer format.
+         */
+        public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = 39;
+        /**
+         * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE
+         * request retransmit interval, for UDP only.
+         * Value is in Integer format.
+         */
+        public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = 40;
+        /**
+         * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction
+         * timeout timer.
+         * Value is in Integer format.
+         */
+        public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = 41;
+        /**
+         * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response
+         * retransmit interval.
+         * Value is in Integer format.
+         */
+        public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = 42;
+        /**
+         * SIP Timer H's value in milliseconds. Timer H is the value of wait time for
+         * ACK receipt.
+         * Value is in Integer format.
+         */
+        public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = 43;
+        /**
+         * SIP Timer I's value in milliseconds. Timer I is the value of wait time for
+         * ACK retransmits.
+         * Value is in Integer format.
+         */
+        public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = 44;
+        /**
+         * SIP Timer J's value in milliseconds. Timer J is the value of wait time for
+         * non-invite request retransmission.
+         * Value is in Integer format.
+         */
+        public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = 45;
+        /**
+         * SIP Timer K's value in milliseconds. Timer K is the value of wait time for
+         * non-invite response retransmits.
+         * Value is in Integer format.
+         */
+        public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = 46;
+        /**
+         * AMR WB octet aligned dynamic payload type.
+         * Value is in Integer format.
+         */
+        public static final int AMR_WB_OCTET_ALIGNED_PT = 47;
+        /**
+         * AMR WB bandwidth efficient payload type.
+         * Value is in Integer format.
+         */
+        public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = 48;
+        /**
+         * AMR octet aligned dynamic payload type.
+         * Value is in Integer format.
+         */
+        public static final int AMR_OCTET_ALIGNED_PT = 49;
+        /**
+         * AMR bandwidth efficient payload type.
+         * Value is in Integer format.
+         */
+        public static final int AMR_BANDWIDTH_EFFICIENT_PT = 50;
+        /**
+         * DTMF WB payload type.
+         * Value is in Integer format.
+         */
+        public static final int DTMF_WB_PT = 51;
+        /**
+         * DTMF NB payload type.
+         * Value is in Integer format.
+         */
+        public static final int DTMF_NB_PT = 52;
+        /**
+         * AMR Default encoding mode.
+         * Value is in Integer format.
+         */
+        public static final int AMR_DEFAULT_MODE = 53;
+        /**
+         * SMS Public Service Identity.
+         * Value is in String format.
+         */
+        public static final int SMS_PSI = 54;
+        /**
+         * Video Quality - VideoQualityFeatureValuesConstants.
+         * Value is in Integer format.
+         */
+        public static final int VIDEO_QUALITY = 55;
+        /**
+         * LTE threshold.
+         * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+         */
+        public static final int TH_LTE1 = 56;
+        /**
+         * LTE threshold.
+         * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+         */
+        public static final int TH_LTE2 = 57;
+        /**
+         * LTE threshold.
+         * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+         */
+        public static final int TH_LTE3 = 58;
+        /**
+         * 1x threshold.
+         * Handover from 1x to WiFi if 1x < TH1x
+         */
+        public static final int TH_1x = 59;
+        /**
+         * WiFi threshold.
+         * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+         */
+        public static final int VOWT_A = 60;
+        /**
+         * WiFi threshold.
+         * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+         */
+        public static final int VOWT_B = 61;
+        /**
+         * LTE ePDG timer.
+         * Device shall not handover back to LTE until the T_ePDG_LTE timer expires.
+         */
+        public static final int T_EPDG_LTE = 62;
+        /**
+         * WiFi ePDG timer.
+         * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires.
+         */
+        public static final int T_EPDG_WIFI = 63;
+        /**
+         * 1x ePDG timer.
+         * Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+         */
+        public static final int T_EPDG_1X = 64;
+        /**
+         * MultiEndpoint status: Enabled (1), or Disabled (0).
+         * Value is in Integer format.
+         */
+        public static final int VICE_SETTING_ENABLED = 65;
+
+        // Expand the operator config items as needed here, need to change
+        // PROVISIONED_CONFIG_END after that.
+        public static final int PROVISIONED_CONFIG_END = VICE_SETTING_ENABLED;
+
+        // Expand the operator config items as needed here.
+    }
+
+    /**
+    * Defines IMS set operation status.
+    */
+    public static class OperationStatusConstants {
+        public static final int UNKNOWN = -1;
+        public static final int SUCCESS = 0;
+        public static final int FAILED =  1;
+        public static final int UNSUPPORTED_CAUSE_NONE = 2;
+        public static final int UNSUPPORTED_CAUSE_RAT = 3;
+        public static final int UNSUPPORTED_CAUSE_DISABLED = 4;
+    }
+
+    /**
+     * Defines IMS get operation values.
+     */
+    public static class OperationValuesConstants {
+        /**
+         * Values related to Video Quality
+         */
+        public static final int VIDEO_QUALITY_UNKNOWN = -1;
+        public static final int VIDEO_QUALITY_LOW = 0;
+        public static final int VIDEO_QUALITY_HIGH = 1;
+    }
+
+    /**
+     * Defines IMS video quality feature value.
+     */
+    public static class VideoQualityFeatureValuesConstants {
+        public static final int LOW = 0;
+        public static final int HIGH = 1;
+    }
+
+   /**
+    * Defines IMS feature value.
+    */
+    public static class FeatureValueConstants {
+        public static final int OFF = 0;
+        public static final int ON = 1;
+    }
+
+    /**
+     * Defines IMS feature value.
+     */
+    public static class WfcModeFeatureValueConstants {
+        public static final int WIFI_ONLY = 0;
+        public static final int CELLULAR_PREFERRED = 1;
+        public static final int WIFI_PREFERRED = 2;
+    }
+
+    public ImsConfig(IImsConfig iconfig, Context context) {
+        if (DBG) Rlog.d(TAG, "ImsConfig creates");
+        miConfig = iconfig;
+        mContext = context;
+    }
+
+    /**
+     * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+     * This function should not be called from the mainthread as it could block the
+     * mainthread.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @return the value in Integer format.
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public int getProvisionedValue(int item) throws ImsException {
+        int ret = 0;
+        try {
+            ret = miConfig.getProvisionedValue(item);
+        }  catch (RemoteException e) {
+            throw new ImsException("getValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        if (DBG) Rlog.d(TAG, "getProvisionedValue(): item = " + item + ", ret =" + ret);
+
+        return ret;
+    }
+
+    /**
+     * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+     * This function should not be called from the mainthread as it could block the
+     * mainthread.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @return value in String format.
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public String getProvisionedStringValue(int item) throws ImsException {
+        String ret = "Unknown";
+        try {
+            ret = miConfig.getProvisionedStringValue(item);
+        }  catch (RemoteException e) {
+            throw new ImsException("getProvisionedStringValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        if (DBG) Rlog.d(TAG, "getProvisionedStringValue(): item = " + item + ", ret =" + ret);
+
+        return ret;
+    }
+
+    /**
+     * Sets the value for IMS service/capabilities parameters by
+     * the operator device management entity.
+     * This function should not be called from main thread as it could block
+     * mainthread.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in Integer format.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public int setProvisionedValue(int item, int value)
+            throws ImsException {
+        int ret = OperationStatusConstants.UNKNOWN;
+        if (DBG) {
+            Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+                    "value = " + value);
+        }
+        try {
+            ret = miConfig.setProvisionedValue(item, value);
+        }  catch (RemoteException e) {
+            throw new ImsException("setProvisionedValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        if (DBG) {
+            Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+                    " value = " + value + " ret = " + ret);
+        }
+        return ret;
+    }
+
+    /**
+     * Sets the value for IMS service/capabilities parameters by
+     * the operator device management entity.
+     * This function should not be called from main thread as it could block
+     * mainthread.
+     *
+     * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+     * @param value in String format.
+     * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public int setProvisionedStringValue(int item, String value)
+            throws ImsException {
+        int ret = OperationStatusConstants.UNKNOWN;
+        try {
+            ret = miConfig.setProvisionedStringValue(item, value);
+        }  catch (RemoteException e) {
+            throw new ImsException("setProvisionedStringValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+        if (DBG) {
+            Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
+                    ", value =" + value);
+        }
+        return ret;
+    }
+
+    /**
+     * Gets the value for IMS feature item for specified network type.
+     *
+     * @param feature, defined as in FeatureConstants.
+     * @param network, defined as in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+     * @param listener, provided to be notified for the feature on/off status.
+     * @return void
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public void getFeatureValue(int feature, int network,
+            ImsConfigListener listener) throws ImsException {
+        if (DBG) {
+            Rlog.d(TAG, "getFeatureValue: feature = " + feature + ", network =" + network +
+                    ", listener =" + listener);
+        }
+        try {
+            miConfig.getFeatureValue(feature, network, listener);
+        } catch (RemoteException e) {
+            throw new ImsException("getFeatureValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+    }
+
+    /**
+     * Sets the value for IMS feature item for specified network type.
+     *
+     * @param feature, as defined in FeatureConstants.
+     * @param network, as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+     * @param value, as defined in FeatureValueConstants.
+     * @param listener, provided if caller needs to be notified for set result.
+     * @return void
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+    public void setFeatureValue(int feature, int network, int value,
+            ImsConfigListener listener) throws ImsException {
+        if (DBG) {
+            Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
+                    ", value =" + value + ", listener =" + listener);
+        }
+        try {
+            miConfig.setFeatureValue(feature, network, value, listener);
+        } catch (RemoteException e) {
+            throw new ImsException("setFeatureValue()", e,
+                    ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+        }
+    }
+}
diff --git a/telephony/java/com/android/ims/ImsException.java b/telephony/java/com/android/ims/ImsException.java
new file mode 100644
index 0000000..74b20f4
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 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.ims;
+
+/**
+ * This class defines a general IMS-related exception.
+ *
+ * @hide
+ */
+public class ImsException extends Exception {
+
+    /**
+     * Refer to CODE_LOCAL_* in {@link ImsReasonInfo}
+     */
+    private int mCode;
+
+    public ImsException() {
+    }
+
+    public ImsException(String message, int code) {
+        super(message + ", code = " + code);
+        mCode = code;
+    }
+
+    public ImsException(String message, Throwable cause, int code) {
+        super(message, cause);
+        mCode = code;
+    }
+
+    /**
+     * Gets the detailed exception code when ImsException is throwed
+     *
+     * @return the exception code in {@link ImsReasonInfo}
+     */
+    public int getCode() {
+        return mCode;
+    }
+}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 56b8822..e4f380f 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -308,6 +308,17 @@
     public static final int CODE_DATA_DISABLED = 1406;
 
     /**
+     * Indicates a call was disconnected due to loss of wifi signal.
+     */
+    public static final int CODE_WIFI_LOST = 1407;
+
+    /**
+     * Indicates the registration attempt on IWLAN failed due to IKEv2 authetication failure
+     * during tunnel establishment.
+     */
+    public static final int CODE_IKEV2_AUTH_FAILURE = 1408;
+
+    /**
      * Network string error messages.
      * mExtraMessage may have these values.
      */
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
new file mode 100644
index 0000000..5984e78
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013 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.ims;
+
+import android.os.Message;
+
+/**
+ * Provides APIs for the supplementary service settings using IMS (Ut interface).
+ * It is created from 3GPP TS 24.623 (XCAP(XML Configuration Access Protocol)
+ * over the Ut interface for manipulating supplementary services).
+ *
+ * @hide
+ */
+public interface ImsUtInterface {
+    /**
+     * Actions
+     * @hide
+     */
+    public static final int ACTION_DEACTIVATION = 0;
+    public static final int ACTION_ACTIVATION = 1;
+    public static final int ACTION_REGISTRATION = 3;
+    public static final int ACTION_ERASURE = 4;
+    public static final int ACTION_INTERROGATION = 5;
+
+    /**
+     * OIR (Originating Identification Restriction, 3GPP TS 24.607)
+     * OIP (Originating Identification Presentation, 3GPP TS 24.607)
+     * TIR (Terminating Identification Restriction, 3GPP TS 24.608)
+     * TIP (Terminating Identification Presentation, 3GPP TS 24.608)
+     */
+    public static final int OIR_DEFAULT = 0;    // "user subscription default value"
+    public static final int OIR_PRESENTATION_RESTRICTED = 1;
+    public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2;
+
+    /**
+     * CW (Communication Waiting, 3GPP TS 24.615)
+     */
+
+    /**
+     * CDIV (Communication Diversion, 3GPP TS 24.604)
+     *     actions: target, no reply timer
+     */
+    public static final int CDIV_CF_UNCONDITIONAL = 0;
+    public static final int CDIV_CF_BUSY = 1;
+    public static final int CDIV_CF_NO_REPLY = 2;
+    public static final int CDIV_CF_NOT_REACHABLE = 3;
+    // For CS service code: 002
+    public static final int CDIV_CF_ALL = 4;
+    // For CS service code: 004
+    public static final int CDIV_CF_ALL_CONDITIONAL = 5;
+    // It's only supported in the IMS service (CS does not define it).
+    // IR.92 recommends that an UE activates both the CFNRc and the CFNL
+    // (CDIV using condition not-registered) to the same target.
+    public static final int CDIV_CF_NOT_LOGGED_IN = 6;
+
+    /**
+     * CB (Communication Barring, 3GPP TS 24.611)
+     */
+    // Barring of All Incoming Calls
+    public static final int CB_BAIC = 1;
+    // Barring of All Outgoing Calls
+    public static final int CB_BAOC = 2;
+    // Barring of Outgoing International Calls
+    public static final int CB_BOIC = 3;
+    // Barring of Outgoing International Calls - excluding Home Country
+    public static final int CB_BOIC_EXHC = 4;
+    // Barring of Incoming Calls - when roaming
+    public static final int CB_BIC_WR = 5;
+    // Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service
+    public static final int CB_BIC_ACR = 6;
+    // Barring of All Calls
+    public static final int CB_BA_ALL = 7;
+    // Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1)
+    public static final int CB_BA_MO = 8;
+    // Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1)
+    public static final int CB_BA_MT = 9;
+    // Barring of Specific Incoming calls
+    public static final int CB_BS_MT = 10;
+
+    /**
+     * Invalid result value.
+     */
+    public static final int INVALID = (-1);
+
+
+
+    /**
+     * Operations for the supplementary service configuration
+     */
+
+    /**
+     * Retrieves the configuration of the call barring.
+     * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+     */
+    public void queryCallBarring(int cbType, Message result);
+
+    /**
+     * Retrieves the configuration of the call forward.
+     * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
+     */
+    public void queryCallForward(int condition, String number, Message result);
+
+    /**
+     * Retrieves the configuration of the call waiting.
+     * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+     */
+    public void queryCallWaiting(Message result);
+
+    /**
+     * Retrieves the default CLIR setting.
+     */
+    public void queryCLIR(Message result);
+
+    /**
+     * Retrieves the CLIP call setting.
+     */
+    public void queryCLIP(Message result);
+
+    /**
+     * Retrieves the COLR call setting.
+     */
+    public void queryCOLR(Message result);
+
+    /**
+     * Retrieves the COLP call setting.
+     */
+    public void queryCOLP(Message result);
+
+    /**
+     * Modifies the configuration of the call barring.
+     */
+    public void updateCallBarring(int cbType, int action,
+            Message result, String[] barrList);
+
+    /**
+     * Modifies the configuration of the call forward.
+     */
+    public void updateCallForward(int action, int condition, String number,
+            int serviceClass, int timeSeconds, Message result);
+
+    /**
+     * Modifies the configuration of the call waiting.
+     */
+    public void updateCallWaiting(boolean enable, int serviceClass, Message result);
+
+    /**
+     * Updates the configuration of the CLIR supplementary service.
+     */
+    public void updateCLIR(int clirMode, Message result);
+
+    /**
+     * Updates the configuration of the CLIP supplementary service.
+     */
+    public void updateCLIP(boolean enable, Message result);
+
+    /**
+     * Updates the configuration of the COLR supplementary service.
+     */
+    public void updateCOLR(int presentation, Message result);
+
+    /**
+     * Updates the configuration of the COLP supplementary service.
+     */
+    public void updateCOLP(boolean enable, Message result);
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
similarity index 60%
copy from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
copy to telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
index 62d5603..41b1042 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
+++ b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot2.pps;
+package com.android.ims.internal;
 
-parcelable HomeSP;
+/**
+*  Interface from ImsFeature in the ImsService to ImsServiceController.
+ * {@hide}
+ */
+oneway interface IImsFeatureStatusCallback {
+    void notifyImsFeatureStatus(int featureStatus);
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index fa86a43..712816f 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -16,10 +16,49 @@
 
 package com.android.ims.internal;
 
+import android.app.PendingIntent;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import android.os.Message;
+
 /**
+ * See ImsService and IMMTelFeature for more information.
  * {@hide}
  */
 interface IImsServiceController {
-    void createImsFeature(int slotId, int feature);
+    // ImsService Control
+    void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
     void removeImsFeature(int slotId, int feature);
+    // MMTel Feature
+    int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent,
+            in IImsRegistrationListener listener);
+    void endSession(int slotId, int featureType, int sessionId);
+    boolean isConnected(int slotId, int featureType, int callSessionType, int callType);
+    boolean isOpened(int slotId, int featureType);
+    int getFeatureStatus(int slotId, int featureType);
+    void addRegistrationListener(int slotId, int featureType, in IImsRegistrationListener listener);
+    void removeRegistrationListener(int slotId, int featureType,
+            in IImsRegistrationListener listener);
+    ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
+            int callSessionType, int callType);
+    IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
+            in ImsCallProfile profile, IImsCallSessionListener listener);
+    IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
+            String callId);
+    IImsUt getUtInterface(int slotId, int featureType);
+    IImsConfig getConfigInterface(int slotId, int featureType);
+    void turnOnIms(int slotId, int featureType);
+    void turnOffIms(int slotId, int featureType);
+    IImsEcbm getEcbmInterface(int slotId, int featureType);
+    void setUiTTYMode(int slotId, int featureType, int uiTtyMode, in Message onComplete);
+    IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
index 0a36b6b..df10700 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
@@ -17,9 +17,12 @@
 package com.android.ims.internal;
 
 /**
+ *  Interface from ImsResolver to ImsServiceProxy in ImsManager.
+ * Callback to ImsManager when a feature changes in the ImsServiceController.
  * {@hide}
  */
 oneway interface IImsServiceFeatureListener {
     void imsFeatureCreated(int slotId, int feature);
     void imsFeatureRemoved(int slotId, int feature);
+    void imsStatusChanged(int slotId, int feature, int status);
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl b/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
index 39e83c6..0da27e1 100644
--- a/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
+++ b/telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl
@@ -43,7 +43,7 @@
 oneway interface IImsVideoCallProvider {
     void setCallback(IImsVideoCallCallback callback);
 
-    void setCamera(String cameraId);
+    void setCamera(String cameraId, int uid);
 
     void setPreviewSurface(in Surface surface);
 
diff --git a/telephony/java/com/android/ims/internal/ImsCallSession.java b/telephony/java/com/android/ims/internal/ImsCallSession.java
new file mode 100644
index 0000000..8196b23
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsCallSession.java
@@ -0,0 +1,1290 @@
+/*
+ * Copyright (c) 2013 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.ims.internal;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import java.util.Objects;
+
+import android.telephony.ims.stub.ImsCallSessionListenerImplBase;
+import android.util.Log;
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+
+/**
+ * Provides the call initiation/termination, and media exchange between two IMS endpoints.
+ * It directly communicates with IMS service which implements the IMS protocol behavior.
+ *
+ * @hide
+ */
+public class ImsCallSession {
+    private static final String TAG = "ImsCallSession";
+
+    /**
+     * Defines IMS call session state.
+     */
+    public static class State {
+        public static final int IDLE = 0;
+        public static final int INITIATED = 1;
+        public static final int NEGOTIATING = 2;
+        public static final int ESTABLISHING = 3;
+        public static final int ESTABLISHED = 4;
+
+        public static final int RENEGOTIATING = 5;
+        public static final int REESTABLISHING = 6;
+
+        public static final int TERMINATING = 7;
+        public static final int TERMINATED = 8;
+
+        public static final int INVALID = (-1);
+
+        /**
+         * Converts the state to string.
+         */
+        public static String toString(int state) {
+            switch (state) {
+                case IDLE:
+                    return "IDLE";
+                case INITIATED:
+                    return "INITIATED";
+                case NEGOTIATING:
+                    return "NEGOTIATING";
+                case ESTABLISHING:
+                    return "ESTABLISHING";
+                case ESTABLISHED:
+                    return "ESTABLISHED";
+                case RENEGOTIATING:
+                    return "RENEGOTIATING";
+                case REESTABLISHING:
+                    return "REESTABLISHING";
+                case TERMINATING:
+                    return "TERMINATING";
+                case TERMINATED:
+                    return "TERMINATED";
+                default:
+                    return "UNKNOWN";
+            }
+        }
+
+        private State() {
+        }
+    }
+
+    /**
+     * Listener for events relating to an IMS session, such as when a session is being
+     * recieved ("on ringing") or a call is outgoing ("on calling").
+     * <p>Many of these events are also received by {@link ImsCall.Listener}.</p>
+     */
+    public static class Listener {
+        /**
+         * Called when a request is sent out to initiate a new session
+         * and 1xx response is received from the network.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionProgressing(ImsCallSession session,
+                ImsStreamMediaProfile profile) {
+            // no-op
+        }
+
+        /**
+         * Called when the session is established.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionStarted(ImsCallSession session,
+                ImsCallProfile profile) {
+            // no-op
+        }
+
+        /**
+         * Called when the session establishment is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the session establishment failure
+         */
+        public void callSessionStartFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the session is terminated.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the session termination
+         */
+        public void callSessionTerminated(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the session is in hold.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionHeld(ImsCallSession session,
+                ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the session hold is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the session hold failure
+         */
+        public void callSessionHoldFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the session hold is received from the remote user.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionHoldReceived(ImsCallSession session,
+                ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the session resume is done.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionResumed(ImsCallSession session,
+                ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the session resume is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the session resume failure
+         */
+        public void callSessionResumeFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the session resume is received from the remote user.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionResumeReceived(ImsCallSession session,
+                ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the session merge has been started.  At this point, the {@code newSession}
+         * represents the session which has been initiated to the IMS conference server for the
+         * new merged conference.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param newSession the session object that is merged with an active & hold session
+         */
+        public void callSessionMergeStarted(ImsCallSession session,
+                ImsCallSession newSession, ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the session merge is successful and the merged session is active.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionMergeComplete(ImsCallSession session) {
+        }
+
+        /**
+         * Called when the session merge has failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the call merge failure
+         */
+        public void callSessionMergeFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the session is updated (except for hold/unhold).
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionUpdated(ImsCallSession session,
+                ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the session update is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the session update failure
+         */
+        public void callSessionUpdateFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the session update is received from the remote user.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionUpdateReceived(ImsCallSession session,
+                ImsCallProfile profile) {
+            // no-op
+        }
+
+        /**
+         * Called when the session is extended to the conference session.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param newSession the session object that is extended to the conference
+         *      from the active session
+         */
+        public void callSessionConferenceExtended(ImsCallSession session,
+                ImsCallSession newSession, ImsCallProfile profile) {
+        }
+
+        /**
+         * Called when the conference extension is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the conference extension failure
+         */
+        public void callSessionConferenceExtendFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+        }
+
+        /**
+         * Called when the conference extension is received from the remote user.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionConferenceExtendReceived(ImsCallSession session,
+                ImsCallSession newSession, ImsCallProfile profile) {
+            // no-op
+        }
+
+        /**
+         * Called when the invitation request of the participants is delivered to the conference
+         * server.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionInviteParticipantsRequestDelivered(ImsCallSession session) {
+            // no-op
+        }
+
+        /**
+         * Called when the invitation request of the participants is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the conference invitation failure
+         */
+        public void callSessionInviteParticipantsRequestFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            // no-op
+        }
+
+        /**
+         * Called when the removal request of the participants is delivered to the conference
+         * server.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionRemoveParticipantsRequestDelivered(ImsCallSession session) {
+            // no-op
+        }
+
+        /**
+         * Called when the removal request of the participants is failed.
+         *
+         * @param session the session object that carries out the IMS session
+         * @param reasonInfo detailed reason of the conference removal failure
+         */
+        public void callSessionRemoveParticipantsRequestFailed(ImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            // no-op
+        }
+
+        /**
+         * Called when the conference state is updated.
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionConferenceStateUpdated(ImsCallSession session,
+                ImsConferenceState state) {
+            // no-op
+        }
+
+        /**
+         * Called when the USSD message is received from the network.
+         *
+         * @param mode mode of the USSD message (REQUEST / NOTIFY)
+         * @param ussdMessage USSD message
+         */
+        public void callSessionUssdMessageReceived(ImsCallSession session,
+                int mode, String ussdMessage) {
+            // no-op
+        }
+
+        /**
+         * Called when session access technology changes
+         *
+         * @param session IMS session object
+         * @param srcAccessTech original access technology
+         * @param targetAccessTech new access technology
+         * @param reasonInfo
+         */
+        public void callSessionHandover(ImsCallSession session,
+                                 int srcAccessTech, int targetAccessTech,
+                                 ImsReasonInfo reasonInfo) {
+            // no-op
+        }
+
+        /**
+         * Called when session access technology change fails
+         *
+         * @param session IMS session object
+         * @param srcAccessTech original access technology
+         * @param targetAccessTech new access technology
+         * @param reasonInfo handover failure reason
+         */
+        public void callSessionHandoverFailed(ImsCallSession session,
+                                       int srcAccessTech, int targetAccessTech,
+                                       ImsReasonInfo reasonInfo) {
+            // no-op
+        }
+
+        /**
+         * Called when TTY mode of remote party changed
+         *
+         * @param session IMS session object
+         * @param mode TTY mode of remote party
+         */
+        public void callSessionTtyModeReceived(ImsCallSession session,
+                                       int mode) {
+            // no-op
+        }
+
+        /**
+         * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+         *
+         * @param session The call session.
+         * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+         *      otherwise.
+         */
+        public void callSessionMultipartyStateChanged(ImsCallSession session,
+                boolean isMultiParty) {
+            // no-op
+        }
+
+        /**
+         * Called when the session supplementary service is received
+         *
+         * @param session the session object that carries out the IMS session
+         */
+        public void callSessionSuppServiceReceived(ImsCallSession session,
+                ImsSuppServiceNotification suppServiceInfo) {
+        }
+    }
+
+    private final IImsCallSession miSession;
+    private boolean mClosed = false;
+    private Listener mListener;
+
+    public ImsCallSession(IImsCallSession iSession) {
+        miSession = iSession;
+
+        if (iSession != null) {
+            try {
+                iSession.setListener(new IImsCallSessionListenerProxy());
+            } catch (RemoteException e) {
+            }
+        } else {
+            mClosed = true;
+        }
+    }
+
+    public ImsCallSession(IImsCallSession iSession, Listener listener) {
+        this(iSession);
+        setListener(listener);
+    }
+
+    /**
+     * Closes this object. This object is not usable after being closed.
+     */
+    public synchronized void close() {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.close();
+            mClosed = true;
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Gets the call ID of the session.
+     *
+     * @return the call ID
+     */
+    public String getCallId() {
+        if (mClosed) {
+            return null;
+        }
+
+        try {
+            return miSession.getCallId();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the call profile that this session is associated with
+     *
+     * @return the call profile that this session is associated with
+     */
+    public ImsCallProfile getCallProfile() {
+        if (mClosed) {
+            return null;
+        }
+
+        try {
+            return miSession.getCallProfile();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the local call profile that this session is associated with
+     *
+     * @return the local call profile that this session is associated with
+     */
+    public ImsCallProfile getLocalCallProfile() {
+        if (mClosed) {
+            return null;
+        }
+
+        try {
+            return miSession.getLocalCallProfile();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the remote call profile that this session is associated with
+     *
+     * @return the remote call profile that this session is associated with
+     */
+    public ImsCallProfile getRemoteCallProfile() {
+        if (mClosed) {
+            return null;
+        }
+
+        try {
+            return miSession.getRemoteCallProfile();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the video call provider for the session.
+     *
+     * @return The video call provider.
+     */
+    public IImsVideoCallProvider getVideoCallProvider() {
+        if (mClosed) {
+            return null;
+        }
+
+        try {
+            return miSession.getVideoCallProvider();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the value associated with the specified property of this session.
+     *
+     * @return the string value associated with the specified property
+     */
+    public String getProperty(String name) {
+        if (mClosed) {
+            return null;
+        }
+
+        try {
+            return miSession.getProperty(name);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the session state.
+     * The value returned must be one of the states in {@link State}.
+     *
+     * @return the session state
+     */
+    public int getState() {
+        if (mClosed) {
+            return State.INVALID;
+        }
+
+        try {
+            return miSession.getState();
+        } catch (RemoteException e) {
+            return State.INVALID;
+        }
+    }
+
+    /**
+     * Determines if the {@link ImsCallSession} is currently alive (e.g. not in a terminated or
+     * closed state).
+     *
+     * @return {@code True} if the session is alive.
+     */
+    public boolean isAlive() {
+        if (mClosed) {
+            return false;
+        }
+
+        int state = getState();
+        switch (state) {
+            case State.IDLE:
+            case State.INITIATED:
+            case State.NEGOTIATING:
+            case State.ESTABLISHING:
+            case State.ESTABLISHED:
+            case State.RENEGOTIATING:
+            case State.REESTABLISHING:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Gets the native IMS call session.
+     * @hide
+     */
+    public IImsCallSession getSession() {
+        return miSession;
+    }
+
+    /**
+     * Checks if the session is in call.
+     *
+     * @return true if the session is in call
+     */
+    public boolean isInCall() {
+        if (mClosed) {
+            return false;
+        }
+
+        try {
+            return miSession.isInCall();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Sets the listener to listen to the session events. A {@link ImsCallSession}
+     * can only hold one listener at a time. Subsequent calls to this method
+     * override the previous listener.
+     *
+     * @param listener to listen to the session events of this object
+     */
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Mutes or unmutes the mic for the active call.
+     *
+     * @param muted true if the call is muted, false otherwise
+     */
+    public void setMute(boolean muted) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.setMute(muted);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Initiates an IMS call with the specified target and call profile.
+     * The session listener is called back upon defined session events.
+     * The method is only valid to call when the session state is in
+     * {@link ImsCallSession.State#IDLE}.
+     *
+     * @param callee dialed string to make the call to
+     * @param profile call profile to make the call with the specified service type,
+     *      call type and media information
+     * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+     */
+    public void start(String callee, ImsCallProfile profile) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.start(callee, profile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Initiates an IMS conference call with the specified target and call profile.
+     * The session listener is called back upon defined session events.
+     * The method is only valid to call when the session state is in
+     * {@link ImsCallSession.State#IDLE}.
+     *
+     * @param participants participant list to initiate an IMS conference call
+     * @param profile call profile to make the call with the specified service type,
+     *      call type and media information
+     * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+     */
+    public void start(String[] participants, ImsCallProfile profile) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.startConference(participants, profile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Accepts an incoming call or session update.
+     *
+     * @param callType call type specified in {@link ImsCallProfile} to be answered
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+     * @see Listener#callSessionStarted
+     */
+    public void accept(int callType, ImsStreamMediaProfile profile) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.accept(callType, profile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Rejects an incoming call or session update.
+     *
+     * @param reason reason code to reject an incoming call
+     * @see Listener#callSessionStartFailed
+     */
+    public void reject(int reason) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.reject(reason);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Terminates a call.
+     *
+     * @see Listener#callSessionTerminated
+     */
+    public void terminate(int reason) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.terminate(reason);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Puts a call on hold. When it succeeds, {@link Listener#callSessionHeld} is called.
+     *
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+     * @see Listener#callSessionHeld, Listener#callSessionHoldFailed
+     */
+    public void hold(ImsStreamMediaProfile profile) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.hold(profile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Continues a call that's on hold. When it succeeds,
+     * {@link Listener#callSessionResumed} is called.
+     *
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to resume the call
+     * @see Listener#callSessionResumed, Listener#callSessionResumeFailed
+     */
+    public void resume(ImsStreamMediaProfile profile) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.resume(profile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Merges the active & hold call. When it succeeds,
+     * {@link Listener#callSessionMergeStarted} is called.
+     *
+     * @see Listener#callSessionMergeStarted , Listener#callSessionMergeFailed
+     */
+    public void merge() {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.merge();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+     *
+     * @param callType call type specified in {@link ImsCallProfile} to be updated
+     * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+     * @see Listener#callSessionUpdated, Listener#callSessionUpdateFailed
+     */
+    public void update(int callType, ImsStreamMediaProfile profile) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.update(callType, profile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Extends this call to the conference call with the specified recipients.
+     *
+     * @param participants list to be invited to the conference call after extending the call
+     * @see Listener#callSessionConferenceExtended
+     * @see Listener#callSessionConferenceExtendFailed
+     */
+    public void extendToConference(String[] participants) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.extendToConference(participants);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Requests the conference server to invite an additional participants to the conference.
+     *
+     * @param participants list to be invited to the conference call
+     * @see Listener#callSessionInviteParticipantsRequestDelivered
+     * @see Listener#callSessionInviteParticipantsRequestFailed
+     */
+    public void inviteParticipants(String[] participants) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.inviteParticipants(participants);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Requests the conference server to remove the specified participants from the conference.
+     *
+     * @param participants participant list to be removed from the conference call
+     * @see Listener#callSessionRemoveParticipantsRequestDelivered
+     * @see Listener#callSessionRemoveParticipantsRequestFailed
+     */
+    public void removeParticipants(String[] participants) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.removeParticipants(participants);
+        } catch (RemoteException e) {
+        }
+    }
+
+
+    /**
+     * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    public void sendDtmf(char c, Message result) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.sendDtmf(c, result);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Starts a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+     * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+     * and event flash to 16. Currently, event flash is not supported.
+     *
+     * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+     */
+    public void startDtmf(char c) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.startDtmf(c);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Stops a DTMF code.
+     */
+    public void stopDtmf() {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.stopDtmf();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sends an USSD message.
+     *
+     * @param ussdMessage USSD message to send
+     */
+    public void sendUssd(String ussdMessage) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.sendUssd(ussdMessage);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Determines if the session is multiparty.
+     *
+     * @return {@code True} if the session is multiparty.
+     */
+    public boolean isMultiparty() {
+        if (mClosed) {
+            return false;
+        }
+
+        try {
+            return miSession.isMultiparty();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * A listener type for receiving notification on IMS call session events.
+     * When an event is generated for an {@link IImsCallSession},
+     * the application is notified by having one of the methods called on
+     * the {@link IImsCallSessionListener}.
+     */
+    private class IImsCallSessionListenerProxy extends ImsCallSessionListenerImplBase {
+        /**
+         * Notifies the result of the basic session operation (setup / terminate).
+         */
+        @Override
+        public void callSessionProgressing(IImsCallSession session,
+                ImsStreamMediaProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionProgressing(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
+        public void callSessionStarted(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionStarted(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
+        public void callSessionStartFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        @Override
+        public void callSessionTerminated(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionTerminated(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        /**
+         * Notifies the result of the call hold/resume operation.
+         */
+        @Override
+        public void callSessionHeld(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionHeld(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
+        public void callSessionHoldFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        @Override
+        public void callSessionHoldReceived(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionHoldReceived(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
+        public void callSessionResumed(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionResumed(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
+        public void callSessionResumeFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        @Override
+        public void callSessionResumeReceived(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionResumeReceived(ImsCallSession.this, profile);
+            }
+        }
+
+        /**
+         * Notifies the start of a call merge operation.
+         *
+         * @param session The call session.
+         * @param newSession The merged call session.
+         * @param profile The call profile.
+         */
+        @Override
+        public void callSessionMergeStarted(IImsCallSession session,
+                IImsCallSession newSession, ImsCallProfile profile) {
+            // This callback can be used for future use to add additional
+            // functionality that may be needed between conference start and complete
+            Log.d(TAG, "callSessionMergeStarted");
+        }
+
+        /**
+         * Notifies the successful completion of a call merge operation.
+         *
+         * @param newSession The call session.
+         */
+        @Override
+        public void callSessionMergeComplete(IImsCallSession newSession) {
+            if (mListener != null) {
+                if (newSession != null) {
+                    // Check if the active session is the same session that was
+                    // active before the merge request was sent.
+                    ImsCallSession validActiveSession = ImsCallSession.this;
+                    try {
+                        if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) {
+                            // New session created after conference
+                            validActiveSession = new ImsCallSession(newSession);
+                        }
+                    } catch (RemoteException rex) {
+                        Log.e(TAG, "callSessionMergeComplete: exception for getCallId!");
+                    }
+                    mListener.callSessionMergeComplete(validActiveSession);
+               } else {
+                   // Session already exists. Hence no need to pass
+                   mListener.callSessionMergeComplete(null);
+               }
+            }
+        }
+
+        /**
+         * Notifies of a failure to perform a call merge operation.
+         *
+         * @param session The call session.
+         * @param reasonInfo The merge failure reason.
+         */
+        @Override
+        public void callSessionMergeFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        /**
+         * Notifies the result of call upgrade / downgrade or any other call updates.
+         */
+        @Override
+        public void callSessionUpdated(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionUpdated(ImsCallSession.this, profile);
+            }
+        }
+
+        @Override
+        public void callSessionUpdateFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        @Override
+        public void callSessionUpdateReceived(IImsCallSession session,
+                ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionUpdateReceived(ImsCallSession.this, profile);
+            }
+        }
+
+        /**
+         * Notifies the result of conference extension.
+         */
+        @Override
+        public void callSessionConferenceExtended(IImsCallSession session,
+                IImsCallSession newSession, ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionConferenceExtended(ImsCallSession.this,
+                        new ImsCallSession(newSession), profile);
+            }
+        }
+
+        @Override
+        public void callSessionConferenceExtendFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionConferenceExtendFailed(ImsCallSession.this, reasonInfo);
+            }
+        }
+
+        @Override
+        public void callSessionConferenceExtendReceived(IImsCallSession session,
+                IImsCallSession newSession, ImsCallProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionConferenceExtendReceived(ImsCallSession.this,
+                        new ImsCallSession(newSession), profile);
+            }
+        }
+
+        /**
+         * Notifies the result of the participant invitation / removal to/from
+         * the conference session.
+         */
+        @Override
+        public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+            if (mListener != null) {
+                mListener.callSessionInviteParticipantsRequestDelivered(ImsCallSession.this);
+            }
+        }
+
+        @Override
+        public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this,
+                        reasonInfo);
+            }
+        }
+
+        @Override
+        public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+            if (mListener != null) {
+                mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this);
+            }
+        }
+
+        @Override
+        public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+                ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this,
+                        reasonInfo);
+            }
+        }
+
+        /**
+         * Notifies the changes of the conference info. in the conference session.
+         */
+        @Override
+        public void callSessionConferenceStateUpdated(IImsCallSession session,
+                ImsConferenceState state) {
+            if (mListener != null) {
+                mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state);
+            }
+        }
+
+        /**
+         * Notifies the incoming USSD message.
+         */
+        @Override
+        public void callSessionUssdMessageReceived(IImsCallSession session,
+                int mode, String ussdMessage) {
+            if (mListener != null) {
+                mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, ussdMessage);
+            }
+        }
+
+        /**
+         * Notifies of handover information for this call
+         */
+        @Override
+        public void callSessionHandover(IImsCallSession session,
+                                 int srcAccessTech, int targetAccessTech,
+                                 ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionHandover(ImsCallSession.this, srcAccessTech,
+                        targetAccessTech, reasonInfo);
+            }
+        }
+
+        /**
+         * Notifies of handover failure info for this call
+         */
+        @Override
+        public void callSessionHandoverFailed(IImsCallSession session,
+                                       int srcAccessTech, int targetAccessTech,
+                                       ImsReasonInfo reasonInfo) {
+            if (mListener != null) {
+                mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech,
+                        targetAccessTech, reasonInfo);
+            }
+        }
+
+        /**
+         * Notifies the TTY mode received from remote party.
+         */
+        @Override
+        public void callSessionTtyModeReceived(IImsCallSession session,
+                int mode) {
+            if (mListener != null) {
+                mListener.callSessionTtyModeReceived(ImsCallSession.this, mode);
+            }
+        }
+
+        /**
+         * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+         *
+         * @param session The call session.
+         * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+         *      otherwise.
+         */
+        public void callSessionMultipartyStateChanged(IImsCallSession session,
+                boolean isMultiParty) {
+
+            if (mListener != null) {
+                mListener.callSessionMultipartyStateChanged(ImsCallSession.this, isMultiParty);
+            }
+        }
+
+        @Override
+        public void callSessionSuppServiceReceived(IImsCallSession session,
+                ImsSuppServiceNotification suppServiceInfo ) {
+            if (mListener != null) {
+                mListener.callSessionSuppServiceReceived(ImsCallSession.this, suppServiceInfo);
+            }
+        }
+
+    }
+
+    /**
+     * Provides a string representation of the {@link ImsCallSession}.  Primarily intended for
+     * use in log statements.
+     *
+     * @return String representation of session.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[ImsCallSession objId:");
+        sb.append(System.identityHashCode(this));
+        sb.append(" state:");
+        sb.append(State.toString(getState()));
+        sb.append(" callId:");
+        sb.append(getCallId());
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
new file mode 100644
index 0000000..432dc39
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
@@ -0,0 +1,294 @@
+/*
+ * 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.ims.internal;
+
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telecom.Connection;
+import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
+import android.view.Surface;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * @hide
+ */
+public abstract class ImsVideoCallProvider {
+    private static final int MSG_SET_CALLBACK = 1;
+    private static final int MSG_SET_CAMERA = 2;
+    private static final int MSG_SET_PREVIEW_SURFACE = 3;
+    private static final int MSG_SET_DISPLAY_SURFACE = 4;
+    private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+    private static final int MSG_SET_ZOOM = 6;
+    private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+    private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+    private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+    private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+    private static final int MSG_SET_PAUSE_IMAGE = 11;
+
+    private final ImsVideoCallProviderBinder mBinder;
+
+    private IImsVideoCallCallback mCallback;
+
+    /**
+     * Default handler used to consolidate binder method calls onto a single thread.
+     */
+    private final Handler mProviderHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_CALLBACK:
+                    mCallback = (IImsVideoCallCallback) msg.obj;
+                    break;
+                case MSG_SET_CAMERA:
+                {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        onSetCamera((String) args.arg1);
+                        onSetCamera((String) args.arg1, args.argi1);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_SET_PREVIEW_SURFACE:
+                    onSetPreviewSurface((Surface) msg.obj);
+                    break;
+                case MSG_SET_DISPLAY_SURFACE:
+                    onSetDisplaySurface((Surface) msg.obj);
+                    break;
+                case MSG_SET_DEVICE_ORIENTATION:
+                    onSetDeviceOrientation(msg.arg1);
+                    break;
+                case MSG_SET_ZOOM:
+                    onSetZoom((Float) msg.obj);
+                    break;
+                case MSG_SEND_SESSION_MODIFY_REQUEST: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        VideoProfile fromProfile = (VideoProfile) args.arg1;
+                        VideoProfile toProfile = (VideoProfile) args.arg2;
+
+                        onSendSessionModifyRequest(fromProfile, toProfile);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
+                case MSG_SEND_SESSION_MODIFY_RESPONSE:
+                    onSendSessionModifyResponse((VideoProfile) msg.obj);
+                    break;
+                case MSG_REQUEST_CAMERA_CAPABILITIES:
+                    onRequestCameraCapabilities();
+                    break;
+                case MSG_REQUEST_CALL_DATA_USAGE:
+                    onRequestCallDataUsage();
+                    break;
+                case MSG_SET_PAUSE_IMAGE:
+                    onSetPauseImage((Uri) msg.obj);
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
+
+    /**
+     * IImsVideoCallProvider stub implementation.
+     */
+    private final class ImsVideoCallProviderBinder extends IImsVideoCallProvider.Stub {
+        public void setCallback(IImsVideoCallCallback callback) {
+            mProviderHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+        }
+
+        public void setCamera(String cameraId, int uid) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = cameraId;
+            args.argi1 = uid;
+            mProviderHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
+        }
+
+        public void setPreviewSurface(Surface surface) {
+            mProviderHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
+        }
+
+        public void setDisplaySurface(Surface surface) {
+            mProviderHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
+        }
+
+        public void setDeviceOrientation(int rotation) {
+            mProviderHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
+        }
+
+        public void setZoom(float value) {
+            mProviderHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
+        }
+
+        public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = fromProfile;
+            args.arg2 = toProfile;
+            mProviderHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
+        }
+
+        public void sendSessionModifyResponse(VideoProfile responseProfile) {
+            mProviderHandler.obtainMessage(
+                    MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
+        }
+
+        public void requestCameraCapabilities() {
+            mProviderHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
+        }
+
+        public void requestCallDataUsage() {
+            mProviderHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget();
+        }
+
+        public void setPauseImage(Uri uri) {
+            mProviderHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
+        }
+    }
+
+    public ImsVideoCallProvider() {
+        mBinder = new ImsVideoCallProviderBinder();
+    }
+
+    /**
+     * Returns binder object which can be used across IPC methods.
+     */
+    public final IImsVideoCallProvider getInterface() {
+        return mBinder;
+    }
+
+    /** @see Connection.VideoProvider#onSetCamera */
+    public abstract void onSetCamera(String cameraId);
+
+    /**
+     * Similar to {@link #onSetCamera(String)}, except includes the UID of the calling process which
+     * the IMS service uses when opening the camera.  This ensures camera permissions are verified
+     * by the camera service.
+     *
+     * @param cameraId The id of the camera to be opened.
+     * @param uid The uid of the caller, used when opening the camera for permission verification.
+     * @see Connection.VideoProvider#onSetCamera
+     */
+    public void onSetCamera(String cameraId, int uid) {
+    }
+
+    /** @see Connection.VideoProvider#onSetPreviewSurface */
+    public abstract void onSetPreviewSurface(Surface surface);
+
+    /** @see Connection.VideoProvider#onSetDisplaySurface */
+    public abstract void onSetDisplaySurface(Surface surface);
+
+    /** @see Connection.VideoProvider#onSetDeviceOrientation */
+    public abstract void onSetDeviceOrientation(int rotation);
+
+    /** @see Connection.VideoProvider#onSetZoom */
+    public abstract void onSetZoom(float value);
+
+    /** @see Connection.VideoProvider#onSendSessionModifyRequest */
+    public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
+            VideoProfile toProfile);
+
+    /** @see Connection.VideoProvider#onSendSessionModifyResponse */
+    public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
+
+    /** @see Connection.VideoProvider#onRequestCameraCapabilities */
+    public abstract void onRequestCameraCapabilities();
+
+    /** @see Connection.VideoProvider#onRequestCallDataUsage */
+    public abstract void onRequestCallDataUsage();
+
+    /** @see Connection.VideoProvider#onSetPauseImage */
+    public abstract void onSetPauseImage(Uri uri);
+
+    /** @see Connection.VideoProvider#receiveSessionModifyRequest */
+    public void receiveSessionModifyRequest(VideoProfile VideoProfile) {
+        if (mCallback != null) {
+            try {
+                mCallback.receiveSessionModifyRequest(VideoProfile);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** @see Connection.VideoProvider#receiveSessionModifyResponse */
+    public void receiveSessionModifyResponse(
+            int status, VideoProfile requestedProfile, VideoProfile responseProfile) {
+        if (mCallback != null) {
+            try {
+                mCallback.receiveSessionModifyResponse(status, requestedProfile, responseProfile);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** @see Connection.VideoProvider#handleCallSessionEvent */
+    public void handleCallSessionEvent(int event) {
+        if (mCallback != null) {
+            try {
+                mCallback.handleCallSessionEvent(event);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** @see Connection.VideoProvider#changePeerDimensions */
+    public void changePeerDimensions(int width, int height) {
+        if (mCallback != null) {
+            try {
+                mCallback.changePeerDimensions(width, height);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** @see Connection.VideoProvider#changeCallDataUsage */
+    public void changeCallDataUsage(long dataUsage) {
+        if (mCallback != null) {
+            try {
+                mCallback.changeCallDataUsage(dataUsage);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** @see Connection.VideoProvider#changeCameraCapabilities */
+    public void changeCameraCapabilities(CameraCapabilities CameraCapabilities) {
+        if (mCallback != null) {
+            try {
+                mCallback.changeCameraCapabilities(CameraCapabilities);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** @see Connection.VideoProvider#changeVideoQuality */
+    public void changeVideoQuality(int videoQuality) {
+        if (mCallback != null) {
+            try {
+                mCallback.changeVideoQuality(videoQuality);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index cbedb95..e9c5461 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -43,6 +43,8 @@
     void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
     void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
     void onVoLteServiceStateChanged(in VoLteServiceState lteState);
+    void onVoiceActivationStateChanged(int activationState);
+    void onDataActivationStateChanged(int activationState);
     void onOemHookRawEvent(in byte[] rawData);
     void onCarrierNetworkChange(in boolean active);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d406cb0..42a80b7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -24,6 +24,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CellInfo;
+import android.telephony.ClientRequestStats;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
@@ -444,6 +445,30 @@
      */
     boolean setVoiceMailNumber(int subId, String alphaTag, String number);
 
+     /**
+      * Sets the voice activation state for a particular subscriber.
+      */
+    void setVoiceActivationState(int subId, int activationState);
+
+     /**
+      * Sets the data activation state for a particular subscriber.
+      */
+    void setDataActivationState(int subId, int activationState);
+
+     /**
+      * Returns the voice activation state for a particular subscriber.
+      * @param subId user preferred sub
+      * @param callingPackage package queries voice activation state
+      */
+    int getVoiceActivationState(int subId, String callingPackage);
+
+     /**
+      * Returns the data activation state for a particular subscriber.
+      * @param subId user preferred sub
+      * @param callingPackage package queris data activation state
+      */
+    int getDataActivationState(int subId, String callingPackage);
+
     /**
       * Returns the unread count of voicemails
       */
@@ -1192,4 +1217,22 @@
      * @hide
      */
     void setPolicyDataEnabled(boolean enabled, int subId);
+
+
+    /**
+     * Get Client request stats which will contain statistical information
+     * on each request made by client.
+     * @param callingPackage package making the call.
+     * @param subId Subscription index
+     * @hide
+     */
+    List<ClientRequestStats> getClientRequestStats(String callingPackage, int subid);
+
+    /**
+     * Set SIM card power state. Request is equivalent to inserting or removing the card.
+     * @param slotId SIM slot id
+     * @param powerUp True if powering up the SIM, otherwise powering down
+     * @hide
+     * */
+    void setSimPowerStateForSlot(int slotId, boolean powerUp);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2c6be62..2c2206c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -65,6 +65,8 @@
             String failCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
     void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
+    void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
+            int activationState, int activationType);
     void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
     void notifySubscriptionInfoChanged();
     void notifyCarrierNetworkChange(in boolean active);
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index fdc68b9..f9de776 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -74,6 +74,9 @@
     public static final int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
     public static final int PRESENTATION_PAYPHONE = 4;   // show pay phone info
 
+    // Sim activation type
+    public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
+    public static final int SIM_ACTIVATION_TYPE_DATA = 1;
 
     public static final String PHONE_NAME_KEY = "phoneName";
     public static final String FAILURE_REASON_KEY = "reason";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index a91e9be..81ecdc9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -411,13 +411,14 @@
     int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
     int RIL_REQUEST_SET_ALLOWED_CARRIERS = 136;
     int RIL_REQUEST_GET_ALLOWED_CARRIERS = 137;
+    int RIL_REQUEST_SET_SIM_CARD_POWER = 140;
 
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
 
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
-    int RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002;
+    int RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED = 1002;
     int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
     int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
     int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 0168874..682b672 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -264,15 +264,6 @@
             = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
 
     /**
-     * Activity Action: Start this activity to invoke the carrier setup app.
-     * The carrier app must be signed using a certificate that matches the UICC access rules.
-     *
-     * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
-     * permission.</p>
-     */
-    public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
-
-    /**
      * <p>Broadcast Action: Indicates that the action is forbidden by network.
      * <p class="note">
      * This is for the OEM applications to understand about possible provisioning issues.
@@ -411,7 +402,7 @@
      * <p class="note">This is a protected intent that can only be sent by the system.</p>
      */
     public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
-            "android.intent.action.CARRIER_SIGNAL_REDIRECTED";
+            "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED";
     /**
      * <p>Broadcast Action: when data connections setup fails.
      * intended for sim/account status checks and only sent to the specified carrier app
@@ -424,7 +415,7 @@
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
     public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
-            "android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+            "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
 
     /**
      * <p>Broadcast Action: when pco value is available.
@@ -441,7 +432,7 @@
      * <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 =
-            "android.intent.action.CARRIER_SIGNAL_PCO_VALUE";
+            "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
 
     // CARRIER_SIGNAL_ACTION extra keys
     public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
diff --git a/test-runner/src/android/test/suitebuilder/TestMethod.java b/test-runner/src/android/test/suitebuilder/TestMethod.java
index 08568d5..ae1db5e 100644
--- a/test-runner/src/android/test/suitebuilder/TestMethod.java
+++ b/test-runner/src/android/test/suitebuilder/TestMethod.java
@@ -26,7 +26,11 @@
 /**
  * Represents a test to be run. Can be constructed without instantiating the TestCase or even
  * loading the class.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class TestMethod {
 
     private final String enclosingClassname;
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 8c89489..3b920cf 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -38,7 +38,11 @@
 /**
  * Build suites based on a combination of included packages, excluded packages,
  * and predicates that must be satisfied.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class TestSuiteBuilder {
 
     private Context context;
@@ -223,7 +227,11 @@
     /**
      * A special {@link junit.framework.TestCase} used to indicate a failure during the build()
      * step.
+     *
+     * @deprecated New tests should be written using the
+     * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
      */
+    @Deprecated
     public static class FailedToCreateTests extends TestCase {
         private final Exception exception;
 
diff --git a/test-runner/src/junit/runner/package-info.java b/test-runner/src/junit/runner/package-info.java
index b746185..364e362 100644
--- a/test-runner/src/junit/runner/package-info.java
+++ b/test-runner/src/junit/runner/package-info.java
@@ -1,4 +1,4 @@
 /**
- * Provides JUnit v3.x test runners.
+ * Utility classes supporting the junit test framework.
  */
 package junit.runner;
\ No newline at end of file
diff --git a/test-runner/src/junit/runner/package.html b/test-runner/src/junit/runner/package.html
deleted file mode 100644
index f08fa70..0000000
--- a/test-runner/src/junit/runner/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-</BODY>
-</HTML>
diff --git a/test-runner/src/junit/textui/package-info.java b/test-runner/src/junit/textui/package-info.java
index 2dcc10c..28b2ef4 100644
--- a/test-runner/src/junit/textui/package-info.java
+++ b/test-runner/src/junit/textui/package-info.java
@@ -1,5 +1,5 @@
 /**
- * Provides JUnit v3.x command line based tool to run tests.
+ * Utility classes supporting the junit test framework.
  * {@hide}
  */
 package junit.textui;
\ No newline at end of file
diff --git a/test-runner/src/junit/textui/package.html b/test-runner/src/junit/textui/package.html
deleted file mode 100644
index 723f2ae..0000000
--- a/test-runner/src/junit/textui/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-{@hide} - Not needed for 1.0 SDK
-</BODY>
-</HTML>
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
new file mode 100644
index 0000000..b984bbf
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityManagerTest {
+    static NetworkCapabilities verifyNetworkCapabilities(
+            int legacyType, int transportType, int... capabilities) {
+        final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
+        assertNotNull(nc);
+        assertTrue(nc.hasTransport(transportType));
+        for (int capability : capabilities) {
+            assertTrue(nc.hasCapability(capability));
+        }
+
+        return nc;
+    }
+
+    static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
+        verifyNetworkCapabilities(
+                legacyType,
+                transportType,
+                NET_CAPABILITY_INTERNET,
+                NET_CAPABILITY_NOT_RESTRICTED,
+                NET_CAPABILITY_NOT_VPN,
+                NET_CAPABILITY_TRUSTED);
+    }
+
+    static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
+        final NetworkCapabilities nc = verifyNetworkCapabilities(
+                legacyType,
+                TRANSPORT_CELLULAR,
+                capability,
+                NET_CAPABILITY_NOT_VPN,
+                NET_CAPABILITY_TRUSTED);
+
+        assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+        assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobile() {
+        verifyUnrestrictedNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileCbs() {
+        verifyRestrictedMobileNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileDun() {
+        verifyRestrictedMobileNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileFota() {
+        verifyRestrictedMobileNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileHipri() {
+        verifyUnrestrictedNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileIms() {
+        verifyRestrictedMobileNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileMms() {
+        final NetworkCapabilities nc = verifyNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_MMS,
+                TRANSPORT_CELLULAR,
+                NET_CAPABILITY_MMS,
+                NET_CAPABILITY_NOT_VPN,
+                NET_CAPABILITY_TRUSTED);
+
+        assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeMobileSupl() {
+        final NetworkCapabilities nc = verifyNetworkCapabilities(
+                ConnectivityManager.TYPE_MOBILE_SUPL,
+                TRANSPORT_CELLULAR,
+                NET_CAPABILITY_SUPL,
+                NET_CAPABILITY_NOT_VPN,
+                NET_CAPABILITY_TRUSTED);
+
+        assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeWifi() {
+        verifyUnrestrictedNetworkCapabilities(
+                ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeWifiP2p() {
+        final NetworkCapabilities nc = verifyNetworkCapabilities(
+                ConnectivityManager.TYPE_WIFI_P2P,
+                TRANSPORT_WIFI,
+                NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
+                NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
+
+        assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeBluetooth() {
+        verifyUnrestrictedNetworkCapabilities(
+                ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
+    }
+
+    @Test
+    public void testNetworkCapabilitiesForTypeEthernet() {
+        verifyUnrestrictedNetworkCapabilities(
+                ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
+    }
+}
diff --git a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
deleted file mode 100644
index f896030..0000000
--- a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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.net;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import java.util.List;
-import junit.framework.TestCase;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class ConnectivityMetricsLoggerTest extends TestCase {
-
-    // use same Parcel object everywhere for pointer equality
-    static final Bundle FAKE_EV = new Bundle();
-    static final int FAKE_COMPONENT = 1;
-    static final int FAKE_EVENT = 2;
-
-    @Mock IConnectivityMetricsLogger mService;
-    ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
-    ArgumentCaptor<ConnectivityMetricsEvent[]> evArrayCaptor;
-
-    ConnectivityMetricsLogger mLog;
-
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
-        evArrayCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent[].class);
-        mLog = new ConnectivityMetricsLogger(mService);
-    }
-
-    @SmallTest
-    public void testLogEvents() throws Exception {
-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-        assertEventsEqual(expectedEvent(2), gotEvents.get(1));
-        assertEventsEqual(expectedEvent(3), gotEvents.get(2));
-    }
-
-    @SmallTest
-    public void testLogEventTriggerThrottling() throws Exception {
-        when(mService.logEvent(any())).thenReturn(1234L);
-
-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-    }
-
-    @SmallTest
-    public void testLogEventFails() throws Exception {
-        when(mService.logEvent(any())).thenReturn(-1L); // Error.
-
-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-    }
-
-    @SmallTest
-    public void testLogEventWhenThrottling() throws Exception {
-        when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
-
-        // No events are logged. The service is only called once
-        // After that, throttling state is maintained locally.
-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-    }
-
-    @SmallTest
-    public void testLogEventRecoverFromThrottling() throws Exception {
-        final long throttleTimeout = System.currentTimeMillis() + 10;
-        when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
-
-        mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-        Thread.sleep(100);
-        mLog.logEvent(53, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
-        List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
-        assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-
-        verify(mService, times(1)).logEvents(evArrayCaptor.capture());
-        ConnectivityMetricsEvent[] gotOtherEvents = evArrayCaptor.getAllValues().get(0);
-        assertEquals(ConnectivityMetricsLogger.TAG_SKIPPED_EVENTS, gotOtherEvents[0].eventTag);
-        assertEventsEqual(expectedEvent(53), gotOtherEvents[1]);
-    }
-
-    List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
-        verify(mService, times(n)).logEvent(evCaptor.capture());
-        return evCaptor.getAllValues();
-    }
-
-    static ConnectivityMetricsEvent expectedEvent(int timestamp) {
-        return new ConnectivityMetricsEvent((long)timestamp, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-    }
-
-    /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
-    static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
-        assertEquals(expected.timestamp, got.timestamp);
-        assertEquals(expected.componentTag, got.componentTag);
-        assertEquals(expected.eventTag, got.eventTag);
-        assertEquals(expected.data, got.data);
-    }
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 39406a11..52d2b63 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -369,6 +369,11 @@
             connect(false);
         }
 
+        public void suspend() {
+            mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
+            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+        }
+
         public void disconnect() {
             mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -1048,6 +1053,7 @@
         AVAILABLE,
         NETWORK_CAPABILITIES,
         LINK_PROPERTIES,
+        SUSPENDED,
         LOSING,
         LOST,
         UNAVAILABLE
@@ -1061,7 +1067,7 @@
             state = s; network = n; arg = o;
         }
         public String toString() {
-            return String.format("%s (%s)", state, network);
+            return String.format("%s (%s) (%s)", state, network, arg);
         }
         @Override
         public boolean equals(Object o) {
@@ -1099,11 +1105,26 @@
         }
 
         @Override
+        public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
+            setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
+        }
+
+        @Override
+        public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
+            setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
+        }
+
+        @Override
         public void onUnavailable() {
             setLastCallback(CallbackState.UNAVAILABLE, null, null);
         }
 
         @Override
+        public void onNetworkSuspended(Network network) {
+            setLastCallback(CallbackState.SUSPENDED, network, null);
+        }
+
+        @Override
         public void onLosing(Network network, int maxMsToLive) {
             setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
         }
@@ -1126,11 +1147,12 @@
             return cb;
         }
 
-        void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
-            CallbackInfo expected = new CallbackInfo(
-                    state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
+        CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
+            final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
+            CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
             CallbackInfo actual = nextCallback(timeoutMs);
             assertEquals("Unexpected callback:", expected, actual);
+
             if (state == CallbackState.LOSING) {
                 String msg = String.format(
                         "Invalid linger time value %d, must be between %d and %d",
@@ -1138,10 +1160,50 @@
                 int maxMsToLive = (Integer) actual.arg;
                 assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
             }
+
+            return actual;
         }
 
-        void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
-            expectCallback(state, mockAgent, TIMEOUT_MS);
+        CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
+            return expectCallback(state, agent, TIMEOUT_MS);
+        }
+
+        void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+            expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
+
+            final boolean HAS_DATASYNC_ON_AVAILABLE = false;
+            if (HAS_DATASYNC_ON_AVAILABLE) {
+                if (expectSuspended) {
+                    expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
+                }
+                expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+                expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+            }
+        }
+
+        void expectAvailableCallbacks(MockNetworkAgent agent) {
+            expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+        }
+
+        void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
+            expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+        }
+
+        void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
+            expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+            expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+        }
+
+        void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
+            CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+            NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+            assertTrue(nc.hasCapability(capability));
+        }
+
+        void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
+            CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+            NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+            assertFalse(nc.hasCapability(capability));
         }
 
         void assertNoCallback() {
@@ -1178,8 +1240,8 @@
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
-        genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         waitFor(cv);
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1193,8 +1255,8 @@
         cv = waitForConnectivityBroadcasts(2);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         waitFor(cv);
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1217,8 +1279,8 @@
         // Test validated networks
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
@@ -1230,9 +1292,10 @@
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
-        wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1268,28 +1331,32 @@
         mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
 
         mCellNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.connect(true);
         // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
         // We then get LOSING when wifi validates and cell is outscored.
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mEthernetNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+        callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+        // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
         assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mEthernetNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
 
         for (int i = 0; i < 4; i++) {
             MockNetworkAgent oldNetwork, newNetwork;
@@ -1306,7 +1373,7 @@
             callback.expectCallback(CallbackState.LOSING, oldNetwork);
             // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
             // longer lingering?
-            defaultCallback.expectCallback(CallbackState.AVAILABLE, newNetwork);
+            defaultCallback.expectAvailableCallbacks(newNetwork);
             assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
         }
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1314,17 +1381,19 @@
         // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
         // if the network is still up.
         mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+        // We expect a notification about the capabilities change, and nothing else.
+        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+        defaultCallback.assertNoCallback();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         // Wifi no longer satisfies our listen, which is for an unmetered network.
         // But because its score is 55, it's still up (and the default network).
-        defaultCallback.assertNoCallback();
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Disconnect our test networks.
         mWiFiNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
 
@@ -1340,22 +1409,22 @@
 
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);   // Score: 10
-        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        callback.expectAvailableCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi with a score of 20.
         // Cell stays up because it would satisfy the default request if it validated.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);   // Score: 20
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi with a score of 70.
@@ -1363,31 +1432,33 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(50);
         mWiFiNetworkAgent.connect(false);   // Score: 70
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Tear down wifi.
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
         // it's arguably correct to linger it, since it was the default network before it validated.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1395,13 +1466,15 @@
         // If a network is lingering, and we add and remove a request from it, resume lingering.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        // TODO: Investigate sending validated before losing.
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
 
         NetworkRequest cellRequest = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_CELLULAR).build();
@@ -1417,7 +1490,7 @@
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
 
         // Cell is now the default network. Pin it with a cell-specific request.
         noopCallback = new NetworkCallback();  // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1426,8 +1499,8 @@
         // Now connect wifi, and expect it to become the default network.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
         // The default request is lingering on cell, but nothing happens to cell, and we send no
         // callbacks for it, because it's kept up by cellRequest.
         callback.assertNoCallback();
@@ -1613,7 +1686,7 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mCellNetworkAgent.connectWithoutInternet();
-        networkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test releasing NetworkRequest disconnects cellular with MMS
         cv = mCellNetworkAgent.getDisconnectedCV();
@@ -1639,7 +1712,7 @@
         MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mmsNetworkAgent.connectWithoutInternet();
-        networkCallback.expectCallback(CallbackState.AVAILABLE, mmsNetworkAgent);
+        networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
         cv = mmsNetworkAgent.getDisconnectedCV();
@@ -1665,7 +1738,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
-        captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
 
         // Take down network.
@@ -1678,7 +1751,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         String secondRedirectUrl = "http://example.com/secondPath";
         mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
-        captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
 
         // Make captive portal disappear then revalidate.
@@ -1688,7 +1761,9 @@
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
-        validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        // TODO: Investigate only sending available callbacks.
+        validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -1733,7 +1808,7 @@
         mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
 
         // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
-        validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         // But there should be no CaptivePortal callback.
         captivePortalCallback.assertNoCallback();
     }
@@ -1786,14 +1861,14 @@
         // Bring up cell and expect CALLBACK_AVAILABLE.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
 
         // Bring up wifi and expect CALLBACK_AVAILABLE.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
         cellNetworkCallback.assertNoCallback();
-        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
 
         // Bring down cell. Expect no default network callback, since it wasn't the default.
         mCellNetworkAgent.disconnect();
@@ -1803,7 +1878,7 @@
         // Bring up cell. Expect no default network callback, since it won't be the default.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         defaultNetworkCallback.assertNoCallback();
 
         // Bring down wifi. Expect the default network callback to notified of LOST wifi
@@ -1811,28 +1886,16 @@
         mWiFiNetworkAgent.disconnect();
         cellNetworkCallback.assertNoCallback();
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
         mCellNetworkAgent.disconnect();
         cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
     }
 
-    private class TestRequestUpdateCallback extends TestNetworkCallback {
-        @Override
-        public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
-            setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
-        }
-
-        @Override
-        public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
-            setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
-        }
-    }
-
     @SmallTest
-    public void testRequestCallbackUpdates() throws Exception {
+    public void testAdditionalStateCallbacks() throws Exception {
         // File a network request for mobile.
-        final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
+        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
         final NetworkRequest cellRequest = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_CELLULAR).build();
         mCm.requestNetwork(cellRequest, cellNetworkCallback);
@@ -1841,10 +1904,10 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
 
-        // We should get onAvailable().
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        // We should get onCapabilitiesChanged(), when the mobile network successfully validates.
-        cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
+        // We should get onAvailable(), onCapabilitiesChanged(), and
+        // onLinkPropertiesChanged() in rapid succession. Additionally, we
+        // should get onCapabilitiesChanged() when the mobile network validates.
+        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
 
         // Update LinkProperties.
@@ -1855,20 +1918,28 @@
         cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
 
+        // Suspend the network.
+        mCellNetworkAgent.suspend();
+        cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+        cellNetworkCallback.assertNoCallback();
+
         // Register a garden variety default network request.
-        final TestNetworkCallback dfltNetworkCallback = new TestRequestUpdateCallback();
+        final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
-        // Only onAvailable() is called; no other information is delivered.
-        dfltNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
+        // as well as onNetworkSuspended() in rapid succession.
+        dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
         dfltNetworkCallback.assertNoCallback();
 
         // Request a NetworkCapabilities update; only the requesting callback is notified.
+        // TODO: Delete this together with Connectivity{Manager,Service} code.
         mCm.requestNetworkCapabilities(dfltNetworkCallback);
         dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
         dfltNetworkCallback.assertNoCallback();
 
         // Request a LinkProperties update; only the requesting callback is notified.
+        // TODO: Delete this together with Connectivity{Manager,Service} code.
         mCm.requestLinkProperties(dfltNetworkCallback);
         dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         cellNetworkCallback.assertNoCallback();
@@ -1911,18 +1982,20 @@
 
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
 
         // When wifi connects, cell lingers.
-        callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
         callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+        fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+        fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
 
@@ -1930,7 +2003,8 @@
         mService.waitForIdle();
         int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
         fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
-        callback.assertNoCallback();
+        // Expect a network capabilities update sans FOREGROUND.
+        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         assertFalse(isForegroundNetwork(mCellNetworkAgent));
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
 
@@ -1939,9 +2013,15 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         final TestNetworkCallback cellCallback = new TestNetworkCallback();
         mCm.requestNetwork(cellRequest, cellCallback);
-        cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        callback.assertNoCallback();  // Because the network is already up.
+        // NOTE: This request causes the network's capabilities to change. This
+        // is currently delivered before the onAvailable() callbacks.
+        // TODO: Fix this.
+        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
+        cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+        // Expect a network capabilities update with FOREGROUND, because the most recent
+        // request causes its state to change.
+        callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
 
@@ -1949,7 +2029,8 @@
         // lingering.
         mCm.unregisterNetworkCallback(cellCallback);
         fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
-        callback.assertNoCallback();
+        // Expect a network capabilities update sans FOREGROUND.
+        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         assertFalse(isForegroundNetwork(mCellNetworkAgent));
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
 
@@ -1957,7 +2038,7 @@
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
-        fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
 
         mCm.unregisterNetworkCallback(callback);
@@ -2098,7 +2179,7 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         testFactory.expectAddRequests(2);  // Because the cell request changes score twice.
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         testFactory.waitForNetworkRequests(2);
         assertFalse(testFactory.getMyStartRequested());  // Because the cell network outscores us.
 
@@ -2189,20 +2270,22 @@
         // Bring up validated cell.
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(true);
-        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
         Network cellNetwork = mCellNetworkAgent.getNetwork();
 
         // Bring up validated wifi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi.
         mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
         mCm.reportNetworkConnectivity(wifiNetwork, false);
+        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         // Because avoid bad wifi is off, we don't switch to cellular.
@@ -2217,18 +2300,18 @@
         // that we switch back to cell.
         tracker.configRestrictsAvoidBadWifi = false;
         tracker.reevaluate();
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
         // Switch back to a restrictive carrier.
         tracker.configRestrictsAvoidBadWifi = true;
         tracker.reevaluate();
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
 
         // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
         mCm.setAvoidUnvalidated(wifiNetwork);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2239,13 +2322,15 @@
         mWiFiNetworkAgent.disconnect();
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
-        validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+        validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+        validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi and expect the dialog to appear.
         mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
         mCm.reportNetworkConnectivity(wifiNetwork, false);
+        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
         // Simulate the user selecting "switch" and checking the don't ask again checkbox.
@@ -2253,7 +2338,7 @@
         tracker.reevaluate();
 
         // We now switch to cell.
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2264,17 +2349,17 @@
         // We switch to wifi and then to cell.
         Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
         tracker.reevaluate();
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), wifiNetwork);
         Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
         tracker.reevaluate();
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
         assertEquals(mCm.getActiveNetwork(), cellNetwork);
 
         // If cell goes down, we switch to wifi.
         mCellNetworkAgent.disconnect();
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
-        defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
         validatedWifiCallback.assertNoCallback();
 
         mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2296,7 +2381,7 @@
 
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
+        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
 
         // pass timeout and validate that UNAVAILABLE is not called
         networkCallback.assertNoCallback();
@@ -2317,7 +2402,7 @@
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         final int assertTimeoutMs = 150;
-        networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
+        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
         sleepFor(20);
         mWiFiNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
diff --git a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
deleted file mode 100644
index 5981f48..0000000
--- a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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 com.android.server.connectivity;
-
-import android.content.Context;
-import android.net.ConnectivityMetricsEvent;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
-import static android.net.ConnectivityMetricsEvent.Reference;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertArrayEquals;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/*
- * TODO:
- *  - allow overriding MetricsLoggerService constants in tests.
- *  - test intents are correctly sent after the notification threshold.
- *  - test oldest events are correctly pushed out when internal deque is full.
- *  - test throttling triggers correctly.
- */
-public class MetricsLoggerServiceTest extends TestCase {
-
-    static final int COMPONENT_TAG = 1;
-    static final long N_EVENTS = 10L;
-    static final ConnectivityMetricsEvent EVENTS[] = new ConnectivityMetricsEvent[(int)N_EVENTS];
-    static {
-        for (int i = 0; i < N_EVENTS; i++) {
-            EVENTS[i] = new ConnectivityMetricsEvent(i, COMPONENT_TAG, i, new Bundle());
-        }
-    }
-
-    static final ConnectivityMetricsEvent NO_EVENTS[] = new ConnectivityMetricsEvent[0];
-
-    @Mock Context mContext;
-    MetricsLoggerService mService;
-
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mService = new MetricsLoggerService(mContext);
-        mService.onStart();
-    }
-
-    @SmallTest
-    public void testGetNoEvents() throws Exception {
-        Reference r = new Reference(0);
-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
-        assertEquals(0, r.getValue());
-    }
-
-    @SmallTest
-    public void testLogAndGetEvents() throws Exception {
-        mService.mBinder.logEvents(EVENTS);
-
-        Reference r = new Reference(0);
-
-        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
-        assertEquals(N_EVENTS, r.getValue());
-
-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
-        assertEquals(N_EVENTS, r.getValue());
-    }
-
-    @SmallTest
-    public void testLogOneByOne() throws Exception {
-        for (ConnectivityMetricsEvent ev : EVENTS) {
-            mService.mBinder.logEvent(ev);
-        }
-
-        Reference r = new Reference(0);
-
-        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
-        assertEquals(N_EVENTS, r.getValue());
-
-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
-        assertEquals(N_EVENTS, r.getValue());
-    }
-
-    @SmallTest
-    public void testInterleavedLogAndGet() throws Exception {
-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
-
-        Reference r = new Reference(0);
-
-        assertArrayEquals(Arrays.copyOfRange(EVENTS, 0, 3), mService.mBinder.getEvents(r));
-        assertEquals(3, r.getValue());
-
-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 8));
-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 8, 10));
-
-        assertArrayEquals(Arrays.copyOfRange(EVENTS, 3, 10), mService.mBinder.getEvents(r));
-        assertEquals(N_EVENTS, r.getValue());
-
-        assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
-        assertEquals(N_EVENTS, r.getValue());
-    }
-
-    @SmallTest
-    public void testMultipleGetAll() throws Exception {
-        mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
-
-        Reference r1 = new Reference(0);
-        assertArrayEquals(Arrays.copyOf(EVENTS, 3), mService.mBinder.getEvents(r1));
-        assertEquals(3, r1.getValue());
-
-        mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 10));
-
-        Reference r2 = new Reference(0);
-        assertArrayEquals(EVENTS, mService.mBinder.getEvents(r2));
-        assertEquals(N_EVENTS, r2.getValue());
-    }
-
-    @SmallTest
-    public void testLogAndDumpConcurrently() throws Exception {
-        for (int i = 0; i < 50; i++) {
-            mContext = null;
-            mService = null;
-            setUp();
-            logAndDumpConcurrently();
-        }
-    }
-
-    public void logAndDumpConcurrently() throws Exception {
-        final CountDownLatch latch = new CountDownLatch((int)N_EVENTS);
-        final FileDescriptor fd = new FileOutputStream("/dev/null").getFD();
-
-        for (ConnectivityMetricsEvent ev : EVENTS) {
-            new Thread() {
-                public void run() {
-                    mService.mBinder.logEvent(ev);
-                    latch.countDown();
-                }
-            }.start();
-        }
-
-        new Thread() {
-            public void run() {
-                while (latch.getCount() > 0) {
-                    mService.mBinder.dump(fd, new String[]{"--all"});
-                }
-            }
-        }.start();
-
-        latch.await(100, TimeUnit.MILLISECONDS);
-
-        Reference r = new Reference(0);
-        ConnectivityMetricsEvent[] got = mService.mBinder.getEvents(r);
-        Arrays.sort(got, new EventComparator());
-        assertArrayEquals(EVENTS, got);
-        assertEquals(N_EVENTS, r.getValue());
-    }
-
-    static class EventComparator implements Comparator<ConnectivityMetricsEvent> {
-        public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
-            return Long.compare(ev1.timestamp, ev2.timestamp);
-        }
-        public boolean equal(Object o) {
-            return o instanceof EventComparator;
-        }
-    };
-}
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 9f7261d..32e1b96 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -28,6 +28,9 @@
 import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+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_TETHERED;
 import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
@@ -92,7 +95,7 @@
     @Test
     public void startsOutAvailable() {
         mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
-                ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+                TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
                 mIPv6TetheringInterfaceServices);
         mTestedSm.start();
         mLooper.dispatchAll();
@@ -103,7 +106,7 @@
 
     @Test
     public void shouldDoNothingUntilRequested() throws Exception {
-        initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+        initStateMachine(TETHERING_BLUETOOTH);
         final int [] NOOP_COMMANDS = {
             TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
             TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
@@ -123,7 +126,7 @@
 
     @Test
     public void handlesImmediateInterfaceDown() throws Exception {
-        initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+        initStateMachine(TETHERING_BLUETOOTH);
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
         verify(mTetherHelper).notifyInterfaceStateChange(
@@ -133,7 +136,7 @@
 
     @Test
     public void canBeTethered() throws Exception {
-        initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+        initStateMachine(TETHERING_BLUETOOTH);
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
         InOrder inOrder = inOrder(mTetherHelper, mNMService);
@@ -145,7 +148,7 @@
 
     @Test
     public void canUnrequestTethering() throws Exception {
-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
+        initTetheredStateMachine(TETHERING_BLUETOOTH, null);
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
         InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
@@ -157,7 +160,7 @@
 
     @Test
     public void canBeTetheredAsUsb() throws Exception {
-        initStateMachine(ConnectivityManager.TETHERING_USB);
+        initStateMachine(TETHERING_USB);
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
         InOrder inOrder = inOrder(mTetherHelper, mNMService);
@@ -171,7 +174,7 @@
 
     @Test
     public void handlesFirstUpstreamChange() throws Exception {
-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
+        initTetheredStateMachine(TETHERING_BLUETOOTH, null);
 
         // Telling the state machine about its upstream interface triggers a little more configuration.
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
@@ -183,7 +186,7 @@
 
     @Test
     public void handlesChangingUpstream() throws Exception {
-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
+        initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
 
         dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
         InOrder inOrder = inOrder(mNMService, mStatsService);
@@ -196,8 +199,44 @@
     }
 
     @Test
+    public void handlesChangingUpstreamNatFailure() throws Exception {
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+        doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
+        InOrder inOrder = inOrder(mNMService, mStatsService);
+        inOrder.verify(mStatsService).forceUpdate();
+        inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
+        inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
+        inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+        inOrder.verify(mStatsService).forceUpdate();
+        inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+        inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+    }
+
+    @Test
+    public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+        doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
+                IFACE_NAME, UPSTREAM_IFACE2);
+
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
+        InOrder inOrder = inOrder(mNMService, mStatsService);
+        inOrder.verify(mStatsService).forceUpdate();
+        inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
+        inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
+        inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+        inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+        inOrder.verify(mStatsService).forceUpdate();
+        inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+        inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+    }
+
+    @Test
     public void canUnrequestTetheringWithUpstream() throws Exception {
-        initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
+        initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
         InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
@@ -213,7 +252,7 @@
     @Test
     public void interfaceDownLeadsToUnavailable() throws Exception {
         for (boolean shouldThrow : new boolean[]{true, false}) {
-            initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
+            initTetheredStateMachine(TETHERING_USB, null);
 
             if (shouldThrow) {
                 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
@@ -230,7 +269,7 @@
 
     @Test
     public void usbShouldBeTornDownOnTetherError() throws Exception {
-        initStateMachine(ConnectivityManager.TETHERING_USB);
+        initStateMachine(TETHERING_USB);
 
         doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
@@ -244,7 +283,7 @@
 
     @Test
     public void shouldTearDownUsbOnUpstreamError() throws Exception {
-        initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
+        initTetheredStateMachine(TETHERING_USB, null);
 
         doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
@@ -255,6 +294,18 @@
                 IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
     }
 
+    @Test
+    public void ignoresDuplicateUpstreamNotifications() throws Exception {
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+        verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+
+        for (int i = 0; i < 5; i++) {
+            dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+            verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+        }
+    }
+
     /**
      * Send a command to the state machine under test, and run the event loop to idle.
      *
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 3ed56df..c72efb0 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -32,6 +32,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.IConnectivityManager;
@@ -42,6 +44,10 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.junit.Test;
@@ -49,6 +55,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -63,6 +70,7 @@
     @Mock private Context mContext;
     @Mock private IConnectivityManager mCS;
 
+    private TestStateMachine mSM;
     private TestConnectivityManager mCM;
     private UpstreamNetworkMonitor mUNM;
 
@@ -72,7 +80,15 @@
         reset(mCS);
 
         mCM = spy(new TestConnectivityManager(mContext, mCS));
-        mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+        mSM = new TestStateMachine();
+        mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+    }
+
+    @After public void tearDown() throws Exception {
+        if (mSM != null) {
+            mSM.quit();
+            mSM = null;
+        }
     }
 
     @Test
@@ -139,15 +155,17 @@
 
         mUNM.start();
         verify(mCM, Mockito.times(1)).registerNetworkCallback(
-                any(NetworkRequest.class), any(NetworkCallback.class));
-        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class));
+                any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+        verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
+                any(NetworkCallback.class), any(Handler.class));
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
         mUNM.updateMobileRequiresDun(true);
         mUNM.registerMobileNetworkRequest();
         verify(mCM, Mockito.times(1)).requestNetwork(
-                any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt());
+                any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
+                any(Handler.class));
 
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
@@ -224,6 +242,7 @@
     }
 
     public static class TestConnectivityManager extends ConnectivityManager {
+        public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
         public Set<NetworkCallback> trackingDefault = new HashSet<>();
         public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
         public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -234,7 +253,8 @@
         }
 
         boolean hasNoCallbacks() {
-            return trackingDefault.isEmpty() &&
+            return allCallbacks.isEmpty() &&
+                   trackingDefault.isEmpty() &&
                    listening.isEmpty() &&
                    requested.isEmpty() &&
                    legacyTypeMap.isEmpty();
@@ -262,14 +282,23 @@
         }
 
         @Override
-        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(requested.containsKey(cb));
             requested.put(cb, req);
         }
 
         @Override
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+            fail("Should never be called.");
+        }
+
+        @Override
         public void requestNetwork(NetworkRequest req, NetworkCallback cb,
-                int timeoutMs, int legacyType) {
+                int timeoutMs, int legacyType, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(requested.containsKey(cb));
             requested.put(cb, req);
             assertFalse(legacyTypeMap.containsKey(cb));
@@ -279,18 +308,32 @@
         }
 
         @Override
-        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(listening.containsKey(cb));
             listening.put(cb, req);
         }
 
         @Override
-        public void registerDefaultNetworkCallback(NetworkCallback cb) {
+        public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+            fail("Should never be called.");
+        }
+
+        @Override
+        public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
+            assertFalse(allCallbacks.containsKey(cb));
+            allCallbacks.put(cb, h);
             assertFalse(trackingDefault.contains(cb));
             trackingDefault.add(cb);
         }
 
         @Override
+        public void registerDefaultNetworkCallback(NetworkCallback cb) {
+            fail("Should never be called.");
+        }
+
+        @Override
         public void unregisterNetworkCallback(NetworkCallback cb) {
             if (trackingDefault.contains(cb)) {
                 trackingDefault.remove(cb);
@@ -302,10 +345,35 @@
             } else {
                 fail("Unexpected callback removed");
             }
+            allCallbacks.remove(cb);
 
+            assertFalse(allCallbacks.containsKey(cb));
             assertFalse(trackingDefault.contains(cb));
             assertFalse(listening.containsKey(cb));
             assertFalse(requested.containsKey(cb));
         }
     }
+
+    public static class TestStateMachine extends StateMachine {
+        public final ArrayList<Message> messages = new ArrayList<>();
+        private final State mLoggingState = new LoggingState();
+
+        class LoggingState extends State {
+            @Override public void enter() { messages.clear(); }
+
+            @Override public void exit() { messages.clear(); }
+
+            @Override public boolean processMessage(Message msg) {
+                messages.add(msg);
+                return true;
+            }
+        }
+
+        public TestStateMachine() {
+            super("UpstreamNetworkMonitor.TestStateMachine");
+            addState(mLoggingState);
+            setInitialState(mLoggingState);
+            super.start();
+        }
+    }
 }
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 7ec46a3e..c5598f0 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -14,7 +14,9 @@
 
 LANG_TO_SCRIPT = {
     'as': 'Beng',
+    'bg': 'Cyrl',
     'bn': 'Beng',
+    'cu': 'Cyrl',
     'cy': 'Latn',
     'da': 'Latn',
     'de': 'Latn',
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index c7f2c41..7611cde 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_JAR_MANIFEST := manifest.txt
 LOCAL_STATIC_JAVA_LIBRARIES := \
-	asm-5.0
+	asm-5.2
 
 LOCAL_MODULE := layoutlib_create
 
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index 61e381d..488d7d6 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_JAVA_LIBRARIES := layoutlib_create junit-host
-LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0
+LOCAL_STATIC_JAVA_LIBRARIES := asm-5.2
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3a45671..2ba573c 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -305,7 +305,9 @@
     /**
      * Priority determines the preference given to a network by {@code wpa_supplicant}
      * when choosing an access point with which to associate.
+     * @deprecated Priority is no longer used.
      */
+    @Deprecated
     public int priority;
 
     /**
@@ -373,6 +375,12 @@
     public String providerFriendlyName;
 
     /**
+     * Flag indicating if this network is provided by a home Passpoint provider or a roaming
+     * Passpoint provider.
+     */
+    public boolean isHomeProviderNetwork;
+
+    /**
      * Roaming Consortium Id list for passpoint credential; identifies a set of networks where
      * passpoint credential will be considered valid
      */
@@ -837,6 +845,7 @@
          * This network is disabled because EAP-TLS failure
          */
         public static final int DISABLED_TLS_VERSION_MISMATCH = 7;
+        // Values above are for temporary disablement; values below are for permanent disablement.
         /**
          * This network is disabled due to absence of user credentials
          */
@@ -961,6 +970,28 @@
         private boolean mHasEverConnected;
 
         /**
+         * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator}
+         * chose not to connect to this network in the last qualified network selection process.
+         */
+        private boolean mNotRecommended;
+
+        /**
+         * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
+         * recommend connecting to this network.
+         */
+        public void setNotRecommended(boolean notRecommended) {
+            mNotRecommended = notRecommended;
+        }
+
+        /**
+         * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
+         * recommend connecting to this network.
+         */
+        public boolean isNotRecommended() {
+            return mNotRecommended;
+        }
+
+        /**
          * set whether this network is visible in latest Qualified Network Selection
          * @param seen value set to candidate
          */
@@ -1264,6 +1295,7 @@
             setConnectChoice(source.getConnectChoice());
             setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
             setHasEverConnected(source.getHasEverConnected());
+            setNotRecommended(source.isNotRecommended());
         }
 
         public void writeToParcel(Parcel dest) {
@@ -1283,6 +1315,7 @@
                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
             }
             dest.writeInt(getHasEverConnected() ? 1 : 0);
+            dest.writeInt(isNotRecommended() ? 1 : 0);
         }
 
         public void readFromParcel(Parcel in) {
@@ -1302,6 +1335,7 @@
                 setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
             }
             setHasEverConnected(in.readInt() != 0);
+            setNotRecommended(in.readInt() != 0);
         }
     }
 
@@ -1881,6 +1915,7 @@
             FQDN = source.FQDN;
             roamingConsortiumIds = source.roamingConsortiumIds.clone();
             providerFriendlyName = source.providerFriendlyName;
+            isHomeProviderNetwork = source.isHomeProviderNetwork;
             preSharedKey = source.preSharedKey;
 
             mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
@@ -1961,6 +1996,7 @@
         dest.writeInt(apChannel);
         dest.writeString(FQDN);
         dest.writeString(providerFriendlyName);
+        dest.writeInt(isHomeProviderNetwork ? 1 : 0);
         dest.writeInt(roamingConsortiumIds.length);
         for (long roamingConsortiumId : roamingConsortiumIds) {
             dest.writeLong(roamingConsortiumId);
@@ -2026,6 +2062,7 @@
                 config.apChannel = in.readInt();
                 config.FQDN = in.readString();
                 config.providerFriendlyName = in.readString();
+                config.isHomeProviderNetwork = in.readInt() != 0;
                 int numRoamingConsortiumIds = in.readInt();
                 config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
                 for (int i = 0; i < numRoamingConsortiumIds; i++) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 0bfb955..f790332 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -263,11 +263,17 @@
         public static final int MSCHAPV2    = 3;
         /** Generic Token Card */
         public static final int GTC         = 4;
+        /** EAP-Subscriber Identity Module */
+        public static final int SIM         = 5;
+        /** EAP-Authentication and Key Agreement */
+        public static final int AKA         = 6;
+        /** EAP-Authentication and Key Agreement Prime */
+        public static final int AKA_PRIME   = 7;
         private static final String AUTH_PREFIX = "auth=";
         private static final String AUTHEAP_PREFIX = "autheap=";
         /** @hide */
         public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
-                "MSCHAPV2", "GTC" };
+                "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'" };
 
         /** Prevent initialization */
         private Phase2() {}
@@ -426,6 +432,9 @@
             case Phase2.MSCHAP:
             case Phase2.MSCHAPV2:
             case Phase2.GTC:
+            case Phase2.SIM:
+            case Phase2.AKA:
+            case Phase2.AKA_PRIME:
                 mPhase2Method = phase2Method;
                 break;
             default:
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ab725e2..ed6a166 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -838,7 +838,8 @@
     }
 
     /**
-     * Return a list of all the networks configured in the supplicant.
+     * Return a list of all the networks configured for the current foreground
+     * user.
      * Not all fields of WifiConfiguration are returned. Only the following
      * fields are filled in:
      * <ul>
@@ -973,7 +974,6 @@
      *
      * @param config The Passpoint configuration to be added
      * @return true on success
-     * @hide
      */
     public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
         try {
@@ -988,7 +988,6 @@
      *
      * @param fqdn The FQDN of the passpoint configuration to be removed
      * @return true on success
-     * @hide
      */
     public boolean removePasspointConfiguration(String fqdn) {
         try {
@@ -1004,7 +1003,6 @@
      * An empty list will be returned when no configurations are installed.
      *
      * @return A list of {@link PasspointConfiguration}
-     * @hide
      */
     public List<PasspointConfiguration> getPasspointConfigurations() {
         try {
@@ -1060,8 +1058,12 @@
      * Remove the specified network from the list of configured networks.
      * This may result in the asynchronous delivery of state change
      * events.
-     * @param netId the integer that identifies the network configuration
-     * to the supplicant
+     *
+     * Applications are not allowed to remove networks created by other
+     * applications.
+     *
+     * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        #getConfiguredNetworks}.
      * @return {@code true} if the operation succeeded
      */
     public boolean removeNetwork(int netId) {
@@ -1074,8 +1076,7 @@
 
     /**
      * Allow a previously configured network to be associated with. If
-     * <code>disableOthers</code> is true, then all other configured
-     * networks are disabled, and an attempt to connect to the selected
+     * <code>attemptConnect</code> is true, an attempt to connect to the selected
      * network is initiated. This may result in the asynchronous delivery
      * of state change events.
      * <p>
@@ -1092,14 +1093,17 @@
      * {@link Network#openConnection(java.net.URL)}, or
      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
      *
-     * @param netId the ID of the network in the list of configured networks
-     * @param disableOthers if true, disable all other networks. The way to
-     * select a particular network to connect to is specify {@code true}
-     * for this parameter.
+     * Applications are not allowed to enable networks created by other
+     * applications.
+     *
+     * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        #getConfiguredNetworks}.
+     * @param attemptConnect The way to select a particular network to connect to is specify
+     *        {@code true} for this parameter.
      * @return {@code true} if the operation succeeded
      */
-    public boolean enableNetwork(int netId, boolean disableOthers) {
-        final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
+    public boolean enableNetwork(int netId, boolean attemptConnect) {
+        final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
         if (pin) {
             NetworkRequest request = new NetworkRequest.Builder()
                     .clearCapabilities()
@@ -1110,7 +1114,7 @@
 
         boolean success;
         try {
-            success = mService.enableNetwork(netId, disableOthers);
+            success = mService.enableNetwork(netId, attemptConnect);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1126,7 +1130,12 @@
      * Disable a configured network. The specified network will not be
      * a candidate for associating. This may result in the asynchronous
      * delivery of state change events.
-     * @param netId the ID of the network as returned by {@link #addNetwork}.
+     *
+     * Applications are not allowed to disable networks created by other
+     * applications.
+     *
+     * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        #getConfiguredNetworks}.
      * @return {@code true} if the operation succeeded
      */
     public boolean disableNetwork(int netId) {
@@ -1185,15 +1194,11 @@
      * Check that the supplicant daemon is responding to requests.
      * @return {@code true} if we were able to communicate with the supplicant and
      * it returned the expected response to the PING message.
+     * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
      */
+    @Deprecated
     public boolean pingSupplicant() {
-        if (mService == null)
-            return false;
-        try {
-            return mService.pingSupplicant();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return isWifiEnabled();
     }
 
     /** @hide */
@@ -1512,14 +1517,18 @@
     }
 
     /**
-     * Tell the supplicant to persist the current list of configured networks.
+     * Tell the device to persist the current list of configured networks.
      * <p>
      * Note: It is possible for this method to change the network IDs of
      * existing networks. You should assume the network IDs can be different
      * after calling this method.
      *
      * @return {@code true} if the operation succeeded
+     * @deprecated There is no need to call this method -
+     * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
+     * and {@link #removeNetwork(int)} already persist the configurations automatically.
      */
+    @Deprecated
     public boolean saveConfiguration() {
         try {
             return mService.saveConfiguration();
@@ -2098,7 +2107,7 @@
 
     /**
      * Connect to a network with the given configuration. The network also
-     * gets added to the supplicant configuration.
+     * gets added to the list of configured networks for the foreground user.
      *
      * For a new network, this function is used instead of a
      * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
@@ -2127,8 +2136,8 @@
      * This function is used instead of a enableNetwork(), saveConfiguration() and
      * reconnect()
      *
-     * @param networkId the network id identifiying the network in the
-     *                supplicant configuration list
+     * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
+     *        getConfiguredNetworks}.
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again
@@ -2140,9 +2149,9 @@
     }
 
     /**
-     * Save the given network in the supplicant config. If the network already
-     * exists, the configuration is updated. A new network is enabled
-     * by default.
+     * Save the given network to the list of configured networks for the
+     * foreground user. If the network already exists, the configuration
+     * is updated. Any new network is enabled by default.
      *
      * For a new network, this function is used instead of a
      * sequence of addNetwork(), enableNetwork() and saveConfiguration().
@@ -2163,7 +2172,8 @@
     }
 
     /**
-     * Delete the network in the supplicant config.
+     * Delete the network from the list of configured networks for the
+     * foreground user.
      *
      * This function is used instead of a sequence of removeNetwork()
      * and saveConfiguration().
@@ -2854,7 +2864,8 @@
 
     /**
      * Restore state from the older version of back up data.
-     * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
+     * The old backup data was essentially a backup of wpa_supplicant.conf
+     * and ipconfig.txt file.
      * @hide
      */
     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index c53cd3c..7a3cddf 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -49,6 +49,14 @@
     private WifiSsid() {
     }
 
+    public static WifiSsid createFromByteArray(byte ssid[]) {
+        WifiSsid wifiSsid = new WifiSsid();
+        if (ssid != null) {
+            wifiSsid.octets.write(ssid, 0/* the start offset */, ssid.length);;
+        }
+        return wifiSsid;
+    }
+
     public static WifiSsid createFromAsciiEncoded(String asciiEncoded) {
         WifiSsid a = new WifiSsid();
         a.convertToBytes(asciiEncoded);
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 6a5957b..cc14ab2 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Arrays;
+
 /**
  * Defines a request object to configure a Wi-Fi Aware network. Built using
  * {@link ConfigRequest.Builder}. Configuration is requested using
@@ -41,6 +43,18 @@
     public static final int CLUSTER_ID_MAX = 0xFFFF;
 
     /**
+     * Indices for configuration variables which are specified per band.
+     */
+    public static final int NAN_BAND_24GHZ = 0;
+    public static final int NAN_BAND_5GHZ = 1;
+
+    /**
+     * Magic values for Discovery Window (DW) interval configuration
+     */
+    public static final int DW_INTERVAL_NOT_INIT = -1;
+    public static final int DW_DISABLE = 0; // only valid for 5GHz
+
+    /**
      * Indicates whether 5G band support is requested.
      */
     public final boolean mSupport5gBand;
@@ -62,19 +76,26 @@
      */
     public final int mClusterHigh;
 
+    /**
+     * Specifies the discovery window interval for the device on NAN_BAND_*.
+     */
+    public final int mDiscoveryWindowInterval[];
+
     private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
-            int clusterHigh) {
+            int clusterHigh, int discoveryWindowInterval[]) {
         mSupport5gBand = support5gBand;
         mMasterPreference = masterPreference;
         mClusterLow = clusterLow;
         mClusterHigh = clusterHigh;
+        mDiscoveryWindowInterval = discoveryWindowInterval;
     }
 
     @Override
     public String toString() {
         return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
                 + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
-                + mClusterHigh + "]";
+                + mClusterHigh + ", mDiscoveryWindowInterval="
+                + Arrays.toString(mDiscoveryWindowInterval) + "]";
     }
 
     @Override
@@ -88,6 +109,7 @@
         dest.writeInt(mMasterPreference);
         dest.writeInt(mClusterLow);
         dest.writeInt(mClusterHigh);
+        dest.writeIntArray(mDiscoveryWindowInterval);
     }
 
     public static final Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() {
@@ -102,7 +124,10 @@
             int masterPreference = in.readInt();
             int clusterLow = in.readInt();
             int clusterHigh = in.readInt();
-            return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh);
+            int discoveryWindowInterval[] = in.createIntArray();
+
+            return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
+                    discoveryWindowInterval);
         }
     };
 
@@ -119,17 +144,8 @@
         ConfigRequest lhs = (ConfigRequest) o;
 
         return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
-                && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
-    }
-
-    /**
-     * Checks whether the configuration's settings are non-default.
-     *
-     * @return true if any of the settings are non-default.
-     */
-    public boolean isNonDefault() {
-        return mSupport5gBand || mMasterPreference != 0 || mClusterLow != CLUSTER_ID_MIN
-                || mClusterHigh != CLUSTER_ID_MAX;
+                && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
+                && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
     }
 
     @Override
@@ -140,6 +156,7 @@
         result = 31 * result + mMasterPreference;
         result = 31 * result + mClusterLow;
         result = 31 * result + mClusterHigh;
+        result = 31 * result + Arrays.hashCode(mDiscoveryWindowInterval);
 
         return result;
     }
@@ -173,6 +190,23 @@
             throw new IllegalArgumentException(
                     "Invalid argument combination - must have Cluster Low <= Cluster High");
         }
+        if (mDiscoveryWindowInterval.length != 2) {
+            throw new IllegalArgumentException(
+                    "Invalid discovery window interval: must have 2 elements (2.4 & 5");
+        }
+        if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
+                (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
+                || mDiscoveryWindowInterval[NAN_BAND_24GHZ] > 5)) {
+            throw new IllegalArgumentException(
+                    "Invalid discovery window interval for 2.4GHz: valid is UNSET or [1,5]");
+        }
+        if (mDiscoveryWindowInterval[NAN_BAND_5GHZ] != DW_INTERVAL_NOT_INIT &&
+                (mDiscoveryWindowInterval[NAN_BAND_5GHZ] < 0 // valid for 5GHz: [0-5]
+                || mDiscoveryWindowInterval[NAN_BAND_5GHZ] > 5)) {
+            throw new IllegalArgumentException(
+                "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
+        }
+
     }
 
     /**
@@ -183,6 +217,7 @@
         private int mMasterPreference = 0;
         private int mClusterLow = CLUSTER_ID_MIN;
         private int mClusterHigh = CLUSTER_ID_MAX;
+        private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
 
         /**
          * Specify whether 5G band support is required in this request. Disabled by default.
@@ -271,6 +306,33 @@
         }
 
         /**
+         * The discovery window interval specifies the discovery windows in which the device will be
+         * awake. The configuration enables trading off latency vs. power (higher interval means
+         * higher discovery latency but lower power).
+         *
+         * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
+         * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
+         *                 the 5GHz band a value of 0 indicates that the device will not be awake
+         *                 for any discovery windows.
+         *
+         * @return The builder itself to facilitate chaining operations
+         *         {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
+         */
+        public Builder setDiscoveryWindowInterval(int band, int interval) {
+            if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
+                throw new IllegalArgumentException("Invalid band value");
+            }
+            if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
+                    || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
+                throw new IllegalArgumentException(
+                        "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
+            }
+
+            mDiscoveryWindowInterval[band] = interval;
+            return this;
+        }
+
+        /**
          * Build {@link ConfigRequest} given the current requests made on the
          * builder.
          */
@@ -280,7 +342,8 @@
                         "Invalid argument combination - must have Cluster Low <= Cluster High");
             }
 
-            return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh);
+            return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
+                    mDiscoveryWindowInterval);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index adf189b..57b98e9 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,8 +31,7 @@
  * {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
  * class provides functionality common to both publish and subscribe discovery sessions:
  * <ul>
- *     <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
- *     {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
+ *     <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])}.
  *     <li>Creating a network-specifier when requesting a Aware connection:
  *     {@link #createNetworkSpecifier(PeerHandle, byte[])}.
  * </ul>
@@ -62,6 +61,8 @@
      * {@link #sendMessage(PeerHandle, int, byte[], int)}.
      *
      * @return Maximum retry count when sending messages.
+     *
+     * @hide
      */
     public static int getMaxSendRetryCount() {
         return MAX_SEND_RETRY_COUNT;
@@ -163,6 +164,8 @@
      *            or MAC level) retries should be attempted if there is no ACK from the receiver
      *            (note: no retransmissions are attempted in other failure cases). A value of 0
      *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
+     *
+     * @hide
      */
     public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
             @Nullable byte[] message, int retryCount) {
@@ -195,8 +198,6 @@
      * The peer will get a callback indicating a message was received using
      * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
      * byte[])}.
-     * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
-     * with a {@code retryCount} of 0.
      *
      * @param peerHandle The peer's handle for the message. Must be a result of an
      * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 33da182..9645b1d 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -124,10 +124,9 @@
     }
 
     /**
-     * Called when message transmission fails - when no ACK is received from the peer.
-     * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
-     * the {@link DiscoverySession#sendMessage(PeerHandle, int,
-     * byte[], int)} method) - this event is received after all retries are exhausted.
+     * Called when message transmission initiated with
+     * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} fails. E.g. when no ACK is
+     * received from the peer.
      * <p>
      * Note that either this callback or
      * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
@@ -141,9 +140,7 @@
 
     /**
      * Called when a message is received from a discovery session peer - in response to the
-     * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
-     * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
-     * int, byte[], int)}.
+     * peer's {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}.
      *
      * @param peerHandle An opaque handle to the peer matching our discovery operation.
      * @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 794c142..0f4910f 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -34,8 +34,6 @@
 interface IWifiAwareManager
 {
     // Aware API
-    void enableUsage();
-    void disableUsage();
     boolean isUsageEnabled();
     Characteristics getCharacteristics();
 
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index a9e38ce..0eb6a3d 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -253,36 +253,6 @@
     }
 
     /**
-     * Enable the usage of the Aware API. Doesn't actually turn on Aware cluster formation - that
-     * only happens when an attach is attempted. {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast
-     * will be triggered.
-     *
-     * @hide
-     */
-    public void enableUsage() {
-        try {
-            mService.enableUsage();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Disable the usage of the Aware API. All attempts to attach() will be rejected. All open
-     * connections and sessions will be terminated. {@link #ACTION_WIFI_AWARE_STATE_CHANGED}
-     * broadcast will be triggered.
-     *
-     * @hide
-     */
-    public void disableUsage() {
-        try {
-            mService.disableUsage();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Returns the current status of Aware API: whether or not Aware is available. To track
      * changes in the state of Aware API register for the
      * {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast.
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
similarity index 97%
rename from wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
rename to wifi/java/android/net/wifi/hotspot2/ConfigParser.java
index 78b335d..027b049a 100644
--- a/wifi/java/android/net/wifi/hotspot2/ConfigBuilder.java
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
@@ -16,7 +16,7 @@
 
 package android.net.wifi.hotspot2;
 
-import android.net.wifi.hotspot2.omadm.PPSMOParser;
+import android.net.wifi.hotspot2.omadm.PpsMoParser;
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Log;
@@ -41,11 +41,9 @@
 
 /**
  * Utility class for building PasspointConfiguration from an installation file.
- *
- * @hide
  */
-public final class ConfigBuilder {
-    private static final String TAG = "ConfigBuilder";
+public final class ConfigParser {
+    private static final String TAG = "ConfigParser";
 
     // Header names.
     private static final String CONTENT_TYPE = "Content-Type";
@@ -101,6 +99,10 @@
         public String encodingType = null;
     }
 
+    /**
+     * @hide
+     */
+    public ConfigParser() {}
 
     /**
      * Parse the Hotspot 2.0 Release 1 configuration data into a {@link PasspointConfiguration}
@@ -133,7 +135,7 @@
      *             certificate chain (optional).
      * @return {@link PasspointConfiguration}
      */
-    public static PasspointConfiguration buildPasspointConfig(String mimeType, byte[] data) {
+    public static PasspointConfiguration parsePasspointConfig(String mimeType, byte[] data) {
         // Verify MIME type.
         if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) {
             Log.e(TAG, "Unexpected MIME type: " + mimeType);
@@ -169,7 +171,7 @@
             throw new IOException("Missing Passpoint Profile");
         }
 
-        PasspointConfiguration config = PPSMOParser.parseMOText(new String(profileData));
+        PasspointConfiguration config = PpsMoParser.parseMoText(new String(profileData));
         if (config == null) {
             throw new IOException("Failed to parse Passpoint profile");
         }
@@ -470,4 +472,4 @@
         }
         return new Pair<PrivateKey, List<X509Certificate>>(clientKey, clientCertificateChain);
     }
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index c2b307d..1f661c4 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -17,7 +17,7 @@
 package android.net.wifi.hotspot2;
 
 import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
 import android.os.Parcelable;
@@ -38,8 +38,6 @@
  *
  * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
  * Release 2 Technical Specification.
- *
- * @hide
  */
 public final class PasspointConfiguration implements Parcelable {
     private static final String TAG = "PasspointConfiguration";
@@ -60,11 +58,11 @@
     private static final int NULL_VALUE = -1;
 
     /**
-     * Configurations under HomeSP subtree.
+     * Configurations under HomeSp subtree.
      */
-    private HomeSP mHomeSp = null;
-    public void setHomeSp(HomeSP homeSp) { mHomeSp = homeSp; }
-    public HomeSP getHomeSp() { return mHomeSp; }
+    private HomeSp mHomeSp = null;
+    public void setHomeSp(HomeSp homeSp) { mHomeSp = homeSp; }
+    public HomeSp getHomeSp() { return mHomeSp; }
 
     /**
      * Configurations under Credential subtree.
@@ -122,7 +120,7 @@
     public void setUpdateIdentifier(int updateIdentifier) {
         mUpdateIdentifier = updateIdentifier;
     }
-    public int getUpdateIdentififer() {
+    public int getUpdateIdentifier() {
         return mUpdateIdentifier;
     }
 
@@ -248,7 +246,7 @@
         }
 
         if (source.mHomeSp != null) {
-            mHomeSp = new HomeSP(source.mHomeSp);
+            mHomeSp = new HomeSp(source.mHomeSp);
         }
         if (source.mCredential != null) {
             mCredential = new Credential(source.mCredential);
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
similarity index 98%
rename from wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
rename to wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
index 24672d4..2ffe428 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
@@ -18,7 +18,7 @@
 
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
 import android.text.TextUtils;
@@ -109,11 +109,9 @@
  *     </Node>
  *   </Node>
  * </MgmtTree>
- *
- * @hide
  */
-public final class PPSMOParser {
-    private static final String TAG = "PPSMOParser";
+public final class PpsMoParser {
+    private static final String TAG = "PpsMoParser";
 
     /**
      * XML tags expected in the PPS MO (PerProviderSubscription Management Object) XML tree.
@@ -326,13 +324,18 @@
     }
 
     /**
+     * @hide
+     */
+    public PpsMoParser() {}
+
+    /**
      * Convert a XML string representation of a PPS MO (PerProviderSubscription
      * Management Object) tree to a {@link PasspointConfiguration} object.
      *
      * @param xmlString XML string representation of a PPS MO tree
      * @return {@link PasspointConfiguration} or null
      */
-    public static PasspointConfiguration parseMOText(String xmlString) {
+    public static PasspointConfiguration parseMoText(String xmlString) {
         // Convert the XML string to a XML tree.
         XMLParser xmlParser = new XMLParser();
         XMLNode root = null;
@@ -640,12 +643,12 @@
      * @return HomeSP
      * @throws ParsingException
      */
-    private static HomeSP parseHomeSP(PPSNode node) throws ParsingException {
+    private static HomeSp parseHomeSP(PPSNode node) throws ParsingException {
         if (node.isLeaf()) {
             throw new ParsingException("Leaf node not expected for HomeSP");
         }
 
-        HomeSP homeSp = new HomeSP();
+        HomeSp homeSp = new HomeSp();
         for (PPSNode child : node.getChildren()) {
             switch (child.getName()) {
                 case NODE_FQDN:
@@ -655,7 +658,7 @@
                     homeSp.setFriendlyName(getPpsNodeValue(child));
                     break;
                 case NODE_ROAMING_CONSORTIUM_OI:
-                    homeSp.setRoamingConsortiumOIs(
+                    homeSp.setRoamingConsortiumOis(
                             parseRoamingConsortiumOI(getPpsNodeValue(child)));
                     break;
                 case NODE_ICON_URL:
@@ -666,8 +669,8 @@
                     break;
                 case NODE_HOME_OI_LIST:
                     Pair<List<Long>, List<Long>> homeOIs = parseHomeOIList(child);
-                    homeSp.setMatchAllOIs(convertFromLongList(homeOIs.first));
-                    homeSp.setMatchAnyOIs(convertFromLongList(homeOIs.second));
+                    homeSp.setMatchAllOis(convertFromLongList(homeOIs.first));
+                    homeSp.setMatchAnyOis(convertFromLongList(homeOIs.second));
                     break;
                 case NODE_OTHER_HOME_PARTNERS:
                     homeSp.setOtherHomePartners(parseOtherHomePartners(child));
@@ -909,7 +912,7 @@
                     credential.setRealm(getPpsNodeValue(child));
                     break;
                 case NODE_CHECK_AAA_SERVER_CERT_STATUS:
-                    credential.setCheckAAAServerCertStatus(
+                    credential.setCheckAaaServerCertStatus(
                             Boolean.parseBoolean(getPpsNodeValue(child)));
                     break;
                 case NODE_SIM:
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index ff93486..620759d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -42,8 +42,6 @@
  *
  * In addition to the fields in the Credential subtree, this will also maintain necessary
  * information for the private key and certificates associated with this credential.
- *
- * @hide
  */
 public final class Credential implements Parcelable {
     private static final String TAG = "Credential";
@@ -98,12 +96,12 @@
      * and Accounting) server's certificate during EAP (Extensible Authentication
      * Protocol) authentication.
      */
-    private boolean mCheckAAAServerCertStatus = false;
-    public void setCheckAAAServerCertStatus(boolean checkAAAServerCertStatus) {
-        mCheckAAAServerCertStatus = checkAAAServerCertStatus;
+    private boolean mCheckAaaServerCertStatus = false;
+    public void setCheckAaaServerCertStatus(boolean checkAaaServerCertStatus) {
+        mCheckAaaServerCertStatus = checkAaaServerCertStatus;
     }
-    public boolean getCheckAAAServerStatus() {
-        return mCheckAAAServerCertStatus;
+    public boolean getCheckAaaServerCertStatus() {
+        return mCheckAaaServerCertStatus;
     }
 
     /**
@@ -685,7 +683,7 @@
             mCreationTimeInMs = source.mCreationTimeInMs;
             mExpirationTimeInMs = source.mExpirationTimeInMs;
             mRealm = source.mRealm;
-            mCheckAAAServerCertStatus = source.mCheckAAAServerCertStatus;
+            mCheckAaaServerCertStatus = source.mCheckAaaServerCertStatus;
             if (source.mUserCredential != null) {
                 mUserCredential = new UserCredential(source.mUserCredential);
             }
@@ -714,7 +712,7 @@
         dest.writeLong(mCreationTimeInMs);
         dest.writeLong(mExpirationTimeInMs);
         dest.writeString(mRealm);
-        dest.writeInt(mCheckAAAServerCertStatus ? 1 : 0);
+        dest.writeInt(mCheckAaaServerCertStatus ? 1 : 0);
         dest.writeParcelable(mUserCredential, flags);
         dest.writeParcelable(mCertCredential, flags);
         dest.writeParcelable(mSimCredential, flags);
@@ -736,7 +734,7 @@
         return TextUtils.equals(mRealm, that.mRealm)
                 && mCreationTimeInMs == that.mCreationTimeInMs
                 && mExpirationTimeInMs == that.mExpirationTimeInMs
-                && mCheckAAAServerCertStatus == that.mCheckAAAServerCertStatus
+                && mCheckAaaServerCertStatus == that.mCheckAaaServerCertStatus
                 && (mUserCredential == null ? that.mUserCredential == null
                     : mUserCredential.equals(that.mUserCredential))
                 && (mCertCredential == null ? that.mCertCredential == null
@@ -751,7 +749,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mRealm, mCreationTimeInMs, mExpirationTimeInMs,
-                mCheckAAAServerCertStatus, mUserCredential, mCertCredential, mSimCredential,
+                mCheckAaaServerCertStatus, mUserCredential, mCertCredential, mSimCredential,
                 mCaCertificate, mClientCertificateChain, mClientPrivateKey);
     }
 
@@ -800,7 +798,7 @@
                 credential.setCreationTimeInMs(in.readLong());
                 credential.setExpirationTimeInMs(in.readLong());
                 credential.setRealm(in.readString());
-                credential.setCheckAAAServerCertStatus(in.readInt() != 0);
+                credential.setCheckAaaServerCertStatus(in.readInt() != 0);
                 credential.setUserCredential(in.readParcelable(null));
                 credential.setCertCredential(in.readParcelable(null));
                 credential.setSimCredential(in.readParcelable(null));
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
similarity index 96%
rename from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
rename to wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
index 62d5603..6d343bd 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.aidl
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.hotspot2.pps;
 
-parcelable HomeSP;
+parcelable HomeSp;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
similarity index 79%
rename from wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
rename to wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 8b3b79c..8ec40c0 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -34,11 +34,9 @@
  *
  * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
  * Release 2 Technical Specification.
- *
- * @hide
  */
-public final class HomeSP implements Parcelable {
-    private static final String TAG = "HomeSP";
+public final class HomeSp implements Parcelable {
+    private static final String TAG = "HomeSp";
 
     /**
      * Maximum number of bytes allowed for a SSID.
@@ -108,12 +106,12 @@
      * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
      * (MO) tree for more detail.
      */
-    private long[] mMatchAllOIs = null;
-    public void setMatchAllOIs(long[] matchAllOIs) {
-        mMatchAllOIs = matchAllOIs;
+    private long[] mMatchAllOis = null;
+    public void setMatchAllOis(long[] matchAllOis) {
+        mMatchAllOis = matchAllOis;
     }
-    public long[] getMatchAllOIs() {
-        return mMatchAllOIs;
+    public long[] getMatchAllOis() {
+        return mMatchAllOis;
     }
 
     /**
@@ -129,12 +127,12 @@
      * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
      * (MO) tree for more detail.
      */
-    private long[] mMatchAnyOIs = null;
-    public void setMatchAnyOIs(long[] matchAnyOIs) {
-        mMatchAnyOIs = matchAnyOIs;
+    private long[] mMatchAnyOis = null;
+    public void setMatchAnyOis(long[] matchAnyOis) {
+        mMatchAnyOis = matchAnyOis;
     }
-    public long[] getMatchAnysOIs() {
-        return mMatchAnyOIs;
+    public long[] getMatchAnyOis() {
+        return mMatchAnyOis;
     }
 
     /**
@@ -155,25 +153,25 @@
      * List of Organization Identifiers (OIs) identifying a roaming consortium of
      * which this provider is a member.
      */
-    private long[] mRoamingConsortiumOIs = null;
-    public void setRoamingConsortiumOIs(long[] roamingConsortiumOIs) {
-        mRoamingConsortiumOIs = roamingConsortiumOIs;
+    private long[] mRoamingConsortiumOis = null;
+    public void setRoamingConsortiumOis(long[] roamingConsortiumOis) {
+        mRoamingConsortiumOis = roamingConsortiumOis;
     }
-    public long[] getRoamingConsortiumOIs() {
-        return mRoamingConsortiumOIs;
+    public long[] getRoamingConsortiumOis() {
+        return mRoamingConsortiumOis;
     }
 
     /**
-     * Constructor for creating HomeSP with default values.
+     * Constructor for creating HomeSp with default values.
      */
-    public HomeSP() {}
+    public HomeSp() {}
 
     /**
      * Copy constructor.
      *
      * @param source The source to copy from
      */
-    public HomeSP(HomeSP source) {
+    public HomeSp(HomeSp source) {
         if (source == null) {
             return;
         }
@@ -183,19 +181,19 @@
         if (source.mHomeNetworkIds != null) {
             mHomeNetworkIds = Collections.unmodifiableMap(source.mHomeNetworkIds);
         }
-        if (source.mMatchAllOIs != null) {
-            mMatchAllOIs = Arrays.copyOf(source.mMatchAllOIs, source.mMatchAllOIs.length);
+        if (source.mMatchAllOis != null) {
+            mMatchAllOis = Arrays.copyOf(source.mMatchAllOis, source.mMatchAllOis.length);
         }
-        if (source.mMatchAnyOIs != null) {
-            mMatchAnyOIs = Arrays.copyOf(source.mMatchAnyOIs, source.mMatchAnyOIs.length);
+        if (source.mMatchAnyOis != null) {
+            mMatchAnyOis = Arrays.copyOf(source.mMatchAnyOis, source.mMatchAnyOis.length);
         }
         if (source.mOtherHomePartners != null) {
             mOtherHomePartners = Arrays.copyOf(source.mOtherHomePartners,
                     source.mOtherHomePartners.length);
         }
-        if (source.mRoamingConsortiumOIs != null) {
-            mRoamingConsortiumOIs = Arrays.copyOf(source.mRoamingConsortiumOIs,
-                    source.mRoamingConsortiumOIs.length);
+        if (source.mRoamingConsortiumOis != null) {
+            mRoamingConsortiumOis = Arrays.copyOf(source.mRoamingConsortiumOis,
+                    source.mRoamingConsortiumOis.length);
         }
     }
 
@@ -210,10 +208,10 @@
         dest.writeString(mFriendlyName);
         dest.writeString(mIconUrl);
         writeHomeNetworkIds(dest, mHomeNetworkIds);
-        dest.writeLongArray(mMatchAllOIs);
-        dest.writeLongArray(mMatchAnyOIs);
+        dest.writeLongArray(mMatchAllOis);
+        dest.writeLongArray(mMatchAnyOis);
         dest.writeStringArray(mOtherHomePartners);
-        dest.writeLongArray(mRoamingConsortiumOIs);
+        dest.writeLongArray(mRoamingConsortiumOis);
     }
 
     @Override
@@ -221,30 +219,30 @@
         if (this == thatObject) {
             return true;
         }
-        if (!(thatObject instanceof HomeSP)) {
+        if (!(thatObject instanceof HomeSp)) {
             return false;
         }
-        HomeSP that = (HomeSP) thatObject;
+        HomeSp that = (HomeSp) thatObject;
 
         return TextUtils.equals(mFqdn, that.mFqdn)
                 && TextUtils.equals(mFriendlyName, that.mFriendlyName)
                 && TextUtils.equals(mIconUrl, that.mIconUrl)
                 && (mHomeNetworkIds == null ? that.mHomeNetworkIds == null
                         : mHomeNetworkIds.equals(that.mHomeNetworkIds))
-                && Arrays.equals(mMatchAllOIs, that.mMatchAllOIs)
-                && Arrays.equals(mMatchAnyOIs, that.mMatchAnyOIs)
+                && Arrays.equals(mMatchAllOis, that.mMatchAllOis)
+                && Arrays.equals(mMatchAnyOis, that.mMatchAnyOis)
                 && Arrays.equals(mOtherHomePartners, that.mOtherHomePartners)
-                && Arrays.equals(mRoamingConsortiumOIs, that.mRoamingConsortiumOIs);
+                && Arrays.equals(mRoamingConsortiumOis, that.mRoamingConsortiumOis);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOIs,
-                mMatchAnyOIs, mOtherHomePartners, mRoamingConsortiumOIs);
+        return Objects.hash(mFqdn, mFriendlyName, mIconUrl, mHomeNetworkIds, mMatchAllOis,
+                mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis);
     }
 
     /**
-     * Validate HomeSP data.
+     * Validate HomeSp data.
      *
      * @return true on success or false on failure
      */
@@ -270,25 +268,25 @@
         return true;
     }
 
-    public static final Creator<HomeSP> CREATOR =
-        new Creator<HomeSP>() {
+    public static final Creator<HomeSp> CREATOR =
+        new Creator<HomeSp>() {
             @Override
-            public HomeSP createFromParcel(Parcel in) {
-                HomeSP homeSp = new HomeSP();
+            public HomeSp createFromParcel(Parcel in) {
+                HomeSp homeSp = new HomeSp();
                 homeSp.setFqdn(in.readString());
                 homeSp.setFriendlyName(in.readString());
                 homeSp.setIconUrl(in.readString());
                 homeSp.setHomeNetworkIds(readHomeNetworkIds(in));
-                homeSp.setMatchAllOIs(in.createLongArray());
-                homeSp.setMatchAnyOIs(in.createLongArray());
+                homeSp.setMatchAllOis(in.createLongArray());
+                homeSp.setMatchAnyOis(in.createLongArray());
                 homeSp.setOtherHomePartners(in.createStringArray());
-                homeSp.setRoamingConsortiumOIs(in.createLongArray());
+                homeSp.setRoamingConsortiumOis(in.createLongArray());
                 return homeSp;
             }
 
             @Override
-            public HomeSP[] newArray(int size) {
-                return new HomeSP[size];
+            public HomeSp[] newArray(int size) {
+                return new HomeSp[size];
             }
 
             /**
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
index ceaada4..63238e8 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -40,18 +40,11 @@
  *
  * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
  * Release 2 Technical Specification.
- *
- * @hide
  */
 public final class Policy implements Parcelable {
     private static final String TAG = "Policy";
 
     /**
-     * Default priority for preferred roaming partner.
-     */
-    public static final int PREFERRED_ROAMING_PARTNER_DEFAULT_PRIORITY = 128;
-
-    /**
      * Maximum number of SSIDs in the exclusion list.
      */
     private static final int MAX_EXCLUSION_SSIDS = 128;
@@ -84,7 +77,7 @@
     public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
         mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
     }
-    public long getMinHomeDownlinkBandWidht() {
+    public long getMinHomeDownlinkBandwidth() {
         return mMinHomeDownlinkBandwidth;
     }
     private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
@@ -189,8 +182,9 @@
 
         /**
          * Priority associated with this roaming partner policy.
+         * Using Integer.MIN_VALUE to indicate unset value.
          */
-        private int mPriority = PREFERRED_ROAMING_PARTNER_DEFAULT_PRIORITY;
+        private int mPriority = Integer.MIN_VALUE;
         public void setPriority(int priority) {
             mPriority = priority;
         }
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
index 17fbf9f..70264b0e 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
@@ -34,8 +34,6 @@
  *
  * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
  * Release 2 Technical Specification.
- *
- * @hide
  */
 public final class UpdateParameter implements Parcelable {
     private static final String TAG = "UpdateParameter";
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 5f949747..632cfaf 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -66,4 +67,35 @@
 
         assertArrayEquals(bytes, rebytes);
     }
+
+    @Test
+    public void testNetworkSelectionStatusCopy() {
+        NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+        networkSelectionStatus.setNotRecommended(true);
+
+        NetworkSelectionStatus copy = new NetworkSelectionStatus();
+        copy.copy(networkSelectionStatus);
+
+        assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+    }
+
+    @Test
+    public void testNetworkSelectionStatusParcel() {
+        NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+        networkSelectionStatus.setNotRecommended(true);
+
+        Parcel parcelW = Parcel.obtain();
+        networkSelectionStatus.writeToParcel(parcelW);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+
+        NetworkSelectionStatus copy = new NetworkSelectionStatus();
+        copy.readFromParcel(parcelR);
+
+        assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index fa546a5..c4d2d32 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -283,6 +283,21 @@
         assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
     }
 
+    /** Verfies PEAP/SIM, PEAP/AKA, PEAP/AKA'. */
+    @Test
+    public void peapSimAkaAkaPrime() {
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.SIM);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=SIM\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setPhase2Method(Phase2.AKA);
+        assertEquals("\"auth=AKA\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setPhase2Method(Phase2.AKA_PRIME);
+        assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
+    }
+
     /** Verfies that the copy constructor preseves the inner method information. */
     @Test
     public void copyConstructor() {
diff --git a/wifi/tests/src/android/net/wifi/WifiSsidTest.java b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
new file mode 100644
index 0000000..c7bdb7b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.wifi;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiSsid}.
+ */
+public class WifiSsidTest {
+
+    private static final byte[] TEST_SSID =
+            new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+    /**
+     * Check that createFromByteArray() works.
+     */
+    @Test
+    public void testCreateFromByteArray() {
+        WifiSsid wifiSsid = WifiSsid.createFromByteArray(TEST_SSID);
+        assertTrue(wifiSsid != null);
+        assertEquals(new String(TEST_SSID), wifiSsid.toString());
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index a396d87..7f68f6f 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -100,26 +100,6 @@
      */
 
     /**
-     * Validate pass-through of enableUsage() API.
-     */
-    @Test
-    public void testEnableUsage() throws Exception {
-        mDut.enableUsage();
-
-        verify(mockAwareService).enableUsage();
-    }
-
-    /**
-     * Validate pass-through of disableUsage() API.
-     */
-    @Test
-    public void testDisableUsage() throws Exception {
-        mDut.disableUsage();
-
-        verify(mockAwareService).disableUsage();
-    }
-
-    /**
      * Validate pass-through of isUsageEnabled() API.
      */
     @Test
@@ -566,6 +546,12 @@
         collector.checkThat("mMasterPreference", 0,
                 equalTo(configRequest.mMasterPreference));
         collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand));
+        collector.checkThat("mDiscoveryWindowInterval.length", 2,
+                equalTo(configRequest.mDiscoveryWindowInterval.length));
+        collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+                equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
+        collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+                equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
     }
 
     @Test
@@ -574,10 +560,12 @@
         final int clusterLow = 5;
         final int masterPreference = 55;
         final boolean supportBand5g = true;
+        final int dwWindow5GHz = 3;
 
         ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
                 .setClusterLow(clusterLow).setMasterPreference(masterPreference)
                 .setSupport5gBand(supportBand5g)
+                .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
                 .build();
 
         collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
@@ -585,6 +573,12 @@
         collector.checkThat("mMasterPreference", masterPreference,
                 equalTo(configRequest.mMasterPreference));
         collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
+        collector.checkThat("mDiscoveryWindowInterval.length", 2,
+                equalTo(configRequest.mDiscoveryWindowInterval.length));
+        collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+                equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
+        collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz,
+                equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -633,16 +627,44 @@
         new ConfigRequest.Builder().setClusterLow(100).setClusterHigh(5).build();
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderDwIntervalInvalidBand() {
+        new ConfigRequest.Builder().setDiscoveryWindowInterval(5, 1).build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderDwIntervalInvalidValueZero() {
+        new ConfigRequest.Builder().setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ,
+                0).build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderDwIntervalInvalidValueLarge() {
+        new ConfigRequest.Builder().setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ,
+                6).build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigRequestBuilderDwIntervalInvalidValueLargeValidate() {
+        ConfigRequest cr = new ConfigRequest.Builder().build();
+        cr.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] = 6;
+        cr.validate();
+    }
+
     @Test
     public void testConfigRequestParcel() {
         final int clusterHigh = 189;
         final int clusterLow = 25;
         final int masterPreference = 177;
         final boolean supportBand5g = true;
+        final int dwWindow24GHz = 1;
+        final int dwWindow5GHz = 5;
 
         ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
                 .setClusterLow(clusterLow).setMasterPreference(masterPreference)
                 .setSupport5gBand(supportBand5g)
+                .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz)
+                .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
                 .build();
 
         Parcel parcelW = Parcel.obtain();
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
similarity index 91%
rename from wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
rename to wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
index f7dbf7e..56bb437 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
@@ -21,7 +21,7 @@
 
 import android.net.wifi.FakeKeys;
 import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.io.BufferedReader;
@@ -33,10 +33,10 @@
 import org.junit.Test;
 
 /**
- * Unit tests for {@link android.net.wifi.hotspot2.ConfigBuilder}.
+ * Unit tests for {@link android.net.wifi.hotspot2.ConfigParser}.
  */
 @SmallTest
-public class ConfigBuilderTest {
+public class ConfigParserTest {
     /**
      * Hotspot 2.0 Release 1 installation file that contains a Passpoint profile and a
      * CA (Certificate Authority) X.509 certificate {@link FakeKeys#CA_CERT0}.
@@ -83,10 +83,10 @@
         PasspointConfiguration config = new PasspointConfiguration();
 
         // HomeSP configuration.
-        HomeSP homeSp = new HomeSP();
+        HomeSp homeSp = new HomeSp();
         homeSp.setFriendlyName("Century House");
         homeSp.setFqdn("mi6.co.uk");
-        homeSp.setRoamingConsortiumOIs(new long[] {0x112233L, 0x445566L});
+        homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
         config.setHomeSp(homeSp);
 
         // Credential configuration.
@@ -123,7 +123,7 @@
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
         PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
         PasspointConfiguration actualConfig =
-                ConfigBuilder.buildPasspointConfig(
+                ConfigParser.parsePasspointConfig(
                         "application/x-wifi-config", configStr.getBytes());
         assertTrue(actualConfig.equals(expectedConfig));
     }
@@ -136,7 +136,7 @@
     @Test
     public void parseConfigFileWithInvalidMimeType() throws Exception {
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT);
-        assertNull(ConfigBuilder.buildPasspointConfig(
+        assertNull(ConfigParser.parsePasspointConfig(
                 "application/wifi-config", configStr.getBytes()));
     }
 
@@ -148,7 +148,7 @@
     @Test
     public void parseConfigFileWithUnencodedData() throws Exception {
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UNENCODED_DATA);
-        assertNull(ConfigBuilder.buildPasspointConfig(
+        assertNull(ConfigParser.parsePasspointConfig(
                 "application/x-wifi-config", configStr.getBytes()));
     }
 
@@ -160,7 +160,7 @@
     @Test
     public void parseConfigFileWithInvalidPart() throws Exception {
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_PART);
-        assertNull(ConfigBuilder.buildPasspointConfig(
+        assertNull(ConfigParser.parsePasspointConfig(
                 "application/x-wifi-config", configStr.getBytes()));
     }
 
@@ -172,7 +172,7 @@
     @Test
     public void parseConfigFileWithMissingBoundary() throws Exception {
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_MISSING_BOUNDARY);
-        assertNull(ConfigBuilder.buildPasspointConfig(
+        assertNull(ConfigParser.parsePasspointConfig(
                 "application/x-wifi-config", configStr.getBytes()));
     }
 
@@ -185,7 +185,7 @@
     @Test
     public void parseConfigFileWithInvalidContentType() throws Exception {
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_INVALID_CONTENT_TYPE);
-        assertNull(ConfigBuilder.buildPasspointConfig(
+        assertNull(ConfigParser.parsePasspointConfig(
                 "application/x-wifi-config", configStr.getBytes()));
     }
 
@@ -197,7 +197,7 @@
     @Test
     public void parseConfigFileWithoutPasspointProfile() throws Exception {
         String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE);
-        assertNull(ConfigBuilder.buildPasspointConfig(
+        assertNull(ConfigParser.parsePasspointConfig(
                 "application/x-wifi-config", configStr.getBytes()));
     }
 }
\ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 3aed918..7df4fcf 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -21,7 +21,7 @@
 
 import android.net.wifi.EAPConstants;
 import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
 import android.os.Parcel;
@@ -50,11 +50,11 @@
      *
      * @return {@link android.net.wifi.hotspot2.pps.HomeSP}
      */
-    private static HomeSP createHomeSp() {
-        HomeSP homeSp = new HomeSP();
+    private static HomeSp createHomeSp() {
+        HomeSp homeSp = new HomeSp();
         homeSp.setFqdn("fqdn");
         homeSp.setFriendlyName("friendly name");
-        homeSp.setRoamingConsortiumOIs(new long[] {0x55, 0x66});
+        homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
         return homeSp;
     }
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
similarity index 91%
rename from wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
rename to wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
index 15de5c7..7cd72f0 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PPSMOParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
@@ -19,10 +19,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.net.wifi.hotspot2.omadm.PPSMOParser;
+import android.net.wifi.hotspot2.omadm.PpsMoParser;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.pps.Credential;
-import android.net.wifi.hotspot2.pps.HomeSP;
+import android.net.wifi.hotspot2.pps.HomeSp;
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -43,10 +43,10 @@
 import java.util.Map;
 
 /**
- * Unit tests for {@link android.net.wifi.hotspot2.omadm.PPSMOParser}.
+ * Unit tests for {@link android.net.wifi.hotspot2.omadm.PpsMoParser}.
  */
 @SmallTest
-public class PPSMOParserTest {
+public class PpsMoParserTest {
     private static final String VALID_PPS_MO_XML_FILE = "assets/pps/PerProviderSubscription.xml";
     private static final String PPS_MO_XML_FILE_DUPLICATE_HOMESP =
             "assets/pps/PerProviderSubscription_DuplicateHomeSP.xml";
@@ -122,17 +122,17 @@
         config.setUsageLimitUsageTimePeriodInMinutes(99910);
 
         // HomeSP configuration.
-        HomeSP homeSp = new HomeSP();
+        HomeSp homeSp = new HomeSp();
         homeSp.setFriendlyName("Century House");
         homeSp.setFqdn("mi6.co.uk");
-        homeSp.setRoamingConsortiumOIs(new long[] {0x112233L, 0x445566L});
+        homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
         homeSp.setIconUrl("icon.test.com");
         Map<String, Long> homeNetworkIds = new HashMap<>();
         homeNetworkIds.put("TestSSID", 0x12345678L);
         homeNetworkIds.put("NullHESSID", null);
         homeSp.setHomeNetworkIds(homeNetworkIds);
-        homeSp.setMatchAllOIs(new long[] {0x11223344});
-        homeSp.setMatchAnyOIs(new long[] {0x55667788});
+        homeSp.setMatchAllOis(new long[] {0x11223344});
+        homeSp.setMatchAnyOis(new long[] {0x55667788});
         homeSp.setOtherHomePartners(new String[] {"other.fqdn.com"});
         config.setHomeSp(homeSp);
 
@@ -141,7 +141,7 @@
         credential.setCreationTimeInMs(format.parse("2016-01-01T10:00:00Z").getTime());
         credential.setExpirationTimeInMs(format.parse("2016-02-01T10:00:00Z").getTime());
         credential.setRealm("shaken.stirred.com");
-        credential.setCheckAAAServerCertStatus(true);
+        credential.setCheckAaaServerCertStatus(true);
         Credential.UserCredential userCredential = new Credential.UserCredential();
         userCredential.setUsername("james");
         userCredential.setPassword("Ym9uZDAwNw==");
@@ -209,53 +209,53 @@
     public void parseValidPPSMOTree() throws Exception {
         String ppsMoTree = loadResourceFile(VALID_PPS_MO_XML_FILE);
         PasspointConfiguration expectedConfig = generateConfigurationFromPPSMOTree();
-        PasspointConfiguration actualConfig = PPSMOParser.parseMOText(ppsMoTree);
+        PasspointConfiguration actualConfig = PpsMoParser.parseMoText(ppsMoTree);
         assertTrue(actualConfig.equals(expectedConfig));
     }
 
     @Test
     public void parseNullPPSMOTree() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(null));
+        assertEquals(null, PpsMoParser.parseMoText(null));
     }
 
     @Test
     public void parseEmptyPPSMOTree() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(new String()));
+        assertEquals(null, PpsMoParser.parseMoText(new String()));
     }
 
     @Test
     public void parsePPSMOTreeWithDuplicateHomeSP() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(
+        assertEquals(null, PpsMoParser.parseMoText(
                 loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_HOMESP)));
     }
 
     @Test
     public void parsePPSMOTreeWithDuplicateValue() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(
+        assertEquals(null, PpsMoParser.parseMoText(
                 loadResourceFile(PPS_MO_XML_FILE_DUPLICATE_VALUE)));
     }
 
     @Test
     public void parsePPSMOTreeWithMissingValue() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(
+        assertEquals(null, PpsMoParser.parseMoText(
                 loadResourceFile(PPS_MO_XML_FILE_MISSING_VALUE)));
     }
 
     @Test
     public void parsePPSMOTreeWithMissingName() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(
+        assertEquals(null, PpsMoParser.parseMoText(
                 loadResourceFile(PPS_MO_XML_FILE_MISSING_NAME)));
     }
 
     @Test
     public void parsePPSMOTreeWithInvalidNode() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(
+        assertEquals(null, PpsMoParser.parseMoText(
                 loadResourceFile(PPS_MO_XML_FILE_INVALID_NODE)));
     }
 
     @Test
     public void parsePPSMOTreeWithInvalidName() throws Exception {
-        assertEquals(null, PPSMOParser.parseMOText(
+        assertEquals(null, PpsMoParser.parseMoText(
                 loadResourceFile(PPS_MO_XML_FILE_INVALID_NAME)));
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 6f68e1c..c7ade00 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -59,7 +59,7 @@
         cred.setCreationTimeInMs(123455L);
         cred.setExpirationTimeInMs(2310093L);
         cred.setRealm("realm");
-        cred.setCheckAAAServerCertStatus(true);
+        cred.setCheckAaaServerCertStatus(true);
         cred.setUserCredential(userCred);
         cred.setCertCredential(certCred);
         cred.setSimCredential(simCred);
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
similarity index 68%
rename from wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
rename to wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
index 92e94ee..c41c11f 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -30,10 +30,10 @@
 import java.util.Map;
 
 /**
- * Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSP}.
+ * Unit tests for {@link android.net.wifi.hotspot2.pps.HomeSp}.
  */
 @SmallTest
-public class HomeSPTest {
+public class HomeSpTest {
 
     /**
      * Helper function for creating a map of home network IDs for testing.
@@ -48,68 +48,68 @@
     }
 
     /**
-     * Helper function for creating a HomeSP for testing.
+     * Helper function for creating a HomeSp for testing.
      *
-     * @param homeNetworkIds The map of home network IDs associated with HomeSP
-     * @return {@link HomeSP}
+     * @param homeNetworkIds The map of home network IDs associated with HomeSp
+     * @return {@link HomeSp}
      */
-    private static HomeSP createHomeSp(Map<String, Long> homeNetworkIds) {
-        HomeSP homeSp = new HomeSP();
+    private static HomeSp createHomeSp(Map<String, Long> homeNetworkIds) {
+        HomeSp homeSp = new HomeSp();
         homeSp.setFqdn("fqdn");
         homeSp.setFriendlyName("friendly name");
         homeSp.setIconUrl("icon.url");
         homeSp.setHomeNetworkIds(homeNetworkIds);
-        homeSp.setMatchAllOIs(new long[] {0x11L, 0x22L});
-        homeSp.setMatchAnyOIs(new long[] {0x33L, 0x44L});
+        homeSp.setMatchAllOis(new long[] {0x11L, 0x22L});
+        homeSp.setMatchAnyOis(new long[] {0x33L, 0x44L});
         homeSp.setOtherHomePartners(new String[] {"partner1", "partner2"});
-        homeSp.setRoamingConsortiumOIs(new long[] {0x55, 0x66});
+        homeSp.setRoamingConsortiumOis(new long[] {0x55, 0x66});
         return homeSp;
     }
 
     /**
-     * Helper function for creating a HomeSP with home network IDs for testing.
+     * Helper function for creating a HomeSp with home network IDs for testing.
      *
-     * @return {@link HomeSP}
+     * @return {@link HomeSp}
      */
-    private static HomeSP createHomeSpWithHomeNetworkIds() {
+    private static HomeSp createHomeSpWithHomeNetworkIds() {
         return createHomeSp(createHomeNetworkIds());
     }
 
     /**
-     * Helper function for creating a HomeSP without home network IDs for testing.
+     * Helper function for creating a HomeSp without home network IDs for testing.
      *
-     * @return {@link HomeSP}
+     * @return {@link HomeSp}
      */
-    private static HomeSP createHomeSpWithoutHomeNetworkIds() {
+    private static HomeSp createHomeSpWithoutHomeNetworkIds() {
         return createHomeSp(null);
     }
 
     /**
-     * Helper function for verifying HomeSP after parcel write then read.
+     * Helper function for verifying HomeSp after parcel write then read.
      * @param writeHomeSp
      * @throws Exception
      */
-    private static void verifyParcel(HomeSP writeHomeSp) throws Exception {
+    private static void verifyParcel(HomeSp writeHomeSp) throws Exception {
         Parcel parcel = Parcel.obtain();
         writeHomeSp.writeToParcel(parcel, 0);
 
         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
-        HomeSP readHomeSp = HomeSP.CREATOR.createFromParcel(parcel);
+        HomeSp readHomeSp = HomeSp.CREATOR.createFromParcel(parcel);
         assertTrue(readHomeSp.equals(writeHomeSp));
     }
 
     /**
-     * Verify parcel read/write for an empty HomeSP.
+     * Verify parcel read/write for an empty HomeSp.
      *
      * @throws Exception
      */
     @Test
-    public void verifyParcelWithEmptyHomeSP() throws Exception {
-        verifyParcel(new HomeSP());
+    public void verifyParcelWithEmptyHomeSp() throws Exception {
+        verifyParcel(new HomeSp());
     }
 
     /**
-     * Verify parcel read/write for a HomeSP containing Home Network IDs.
+     * Verify parcel read/write for a HomeSp containing Home Network IDs.
      *
      * @throws Exception
      */
@@ -119,7 +119,7 @@
     }
 
     /**
-     * Verify parcel read/write for a HomeSP without Home Network IDs.
+     * Verify parcel read/write for a HomeSp without Home Network IDs.
      *
      * @throws Exception
      */
@@ -129,62 +129,62 @@
     }
 
     /**
-     * Verify that a HomeSP is valid when both FQDN and Friendly Name
+     * Verify that a HomeSp is valid when both FQDN and Friendly Name
      * are provided.
      *
      * @throws Exception
      */
     @Test
-    public void validateValidHomeSP() throws Exception {
-        HomeSP homeSp = createHomeSpWithHomeNetworkIds();
+    public void validateValidHomeSp() throws Exception {
+        HomeSp homeSp = createHomeSpWithHomeNetworkIds();
         assertTrue(homeSp.validate());
     }
 
     /**
-     * Verify that a HomeSP is not valid when FQDN is not provided
+     * Verify that a HomeSp is not valid when FQDN is not provided
      *
      * @throws Exception
      */
     @Test
     public void validateHomeSpWithoutFqdn() throws Exception {
-        HomeSP homeSp = createHomeSpWithHomeNetworkIds();
+        HomeSp homeSp = createHomeSpWithHomeNetworkIds();
         homeSp.setFqdn(null);
         assertFalse(homeSp.validate());
     }
 
     /**
-     * Verify that a HomeSP is not valid when Friendly Name is not provided
+     * Verify that a HomeSp is not valid when Friendly Name is not provided
      *
      * @throws Exception
      */
     @Test
     public void validateHomeSpWithoutFriendlyName() throws Exception {
-        HomeSP homeSp = createHomeSpWithHomeNetworkIds();
+        HomeSp homeSp = createHomeSpWithHomeNetworkIds();
         homeSp.setFriendlyName(null);
         assertFalse(homeSp.validate());
     }
 
     /**
-     * Verify that a HomeSP is valid when the optional Home Network IDs are
+     * Verify that a HomeSp is valid when the optional Home Network IDs are
      * not provided.
      *
      * @throws Exception
      */
     @Test
     public void validateHomeSpWithoutHomeNetworkIds() throws Exception {
-        HomeSP homeSp = createHomeSpWithoutHomeNetworkIds();
+        HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
         assertTrue(homeSp.validate());
     }
 
     /**
-     * Verify that a HomeSP is invalid when the optional Home Network IDs
+     * Verify that a HomeSp is invalid when the optional Home Network IDs
      * contained an invalid SSID (exceeding maximum number of bytes).
      *
      * @throws Exception
      */
     @Test
     public void validateHomeSpWithInvalidHomeNetworkIds() throws Exception {
-        HomeSP homeSp = createHomeSpWithoutHomeNetworkIds();
+        HomeSp homeSp = createHomeSpWithoutHomeNetworkIds();
         // HomeNetworkID with SSID exceeding the maximum length.
         Map<String, Long> homeNetworkIds = new HashMap<>();
         byte[] rawSsidBytes = new byte[33];
@@ -202,8 +202,8 @@
      */
     @Test
     public void validateCopyConstructorFromNullSource() throws Exception {
-        HomeSP copySp = new HomeSP(null);
-        HomeSP defaultSp = new HomeSP();
+        HomeSp copySp = new HomeSp(null);
+        HomeSp defaultSp = new HomeSp();
         assertTrue(copySp.equals(defaultSp));
     }
 
@@ -214,8 +214,8 @@
      */
     @Test
     public void validateCopyConstructorFromValidSource() throws Exception {
-        HomeSP sourceSp = createHomeSpWithHomeNetworkIds();
-        HomeSP copySp = new HomeSP(sourceSp);
+        HomeSp sourceSp = createHomeSpWithHomeNetworkIds();
+        HomeSp copySp = new HomeSp(sourceSp);
         assertTrue(copySp.equals(sourceSp));
     }
 }