Merge "Add UI prompt for MMI code failure on 3gpp"
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 3efbb2d..717bb29 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24737,11 +24737,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 {
@@ -25027,7 +25030,7 @@
     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 getUpdateIdentififer();
+    method public int getUpdateIdentifier();
     method public long getUsageLimitDataLimit();
     method public long getUsageLimitStartTimeInMs();
     method public long getUsageLimitTimeLimitInMinutes();
@@ -25069,7 +25072,7 @@
     method public int describeContents();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
-    method public boolean getCheckAaaServerStatus();
+    method public boolean getCheckAaaServerCertStatus();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
     method public long getCreationTimeInMs();
@@ -25150,7 +25153,7 @@
     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[] getMatchAnysOis();
+    method public long[] getMatchAnyOis();
     method public java.lang.String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(java.lang.String);
@@ -25172,7 +25175,7 @@
     method public int describeContents();
     method public java.lang.String[] getExcludedSsidList();
     method public int getMaximumBssLoadValue();
-    method public long getMinHomeDownlinkBandWidht();
+    method public long getMinHomeDownlinkBandwidth();
     method public long getMinHomeUplinkBandwidth();
     method public long getMinRoamingDownlinkBandwidth();
     method public long getMinRoamingUplinkBandwidth();
@@ -36578,9 +36581,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);
@@ -36592,9 +36597,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);
@@ -36621,6 +36629,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);
   }
@@ -36674,6 +36685,19 @@
     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 static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
@@ -37045,6 +37069,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
@@ -37257,6 +37282,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";
@@ -49267,6 +49293,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
@@ -50675,6 +50703,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;
@@ -52561,6 +52596,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);
@@ -52646,7 +52696,6 @@
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
     method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
-    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
     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;
@@ -52689,6 +52738,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 2407c7ad..51e25c1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27110,11 +27110,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 {
@@ -27580,7 +27583,7 @@
     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 getUpdateIdentififer();
+    method public int getUpdateIdentifier();
     method public long getUsageLimitDataLimit();
     method public long getUsageLimitStartTimeInMs();
     method public long getUsageLimitTimeLimitInMinutes();
@@ -27622,7 +27625,7 @@
     method public int describeContents();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
-    method public boolean getCheckAaaServerStatus();
+    method public boolean getCheckAaaServerCertStatus();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
     method public long getCreationTimeInMs();
@@ -27703,7 +27706,7 @@
     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[] getMatchAnysOis();
+    method public long[] getMatchAnyOis();
     method public java.lang.String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(java.lang.String);
@@ -27725,7 +27728,7 @@
     method public int describeContents();
     method public java.lang.String[] getExcludedSsidList();
     method public int getMaximumBssLoadValue();
-    method public long getMinHomeDownlinkBandWidht();
+    method public long getMinHomeDownlinkBandwidth();
     method public long getMinHomeUplinkBandwidth();
     method public long getMinRoamingDownlinkBandwidth();
     method public long getMinRoamingUplinkBandwidth();
@@ -39545,9 +39548,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);
@@ -39560,9 +39565,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);
@@ -39590,6 +39598,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);
   }
@@ -39647,6 +39658,19 @@
     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 static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
@@ -40149,6 +40173,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
@@ -40425,6 +40450,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";
@@ -52888,6 +52914,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
@@ -54296,6 +54324,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;
@@ -56182,6 +56217,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);
@@ -56267,7 +56317,6 @@
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
     method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
-    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
     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;
@@ -56310,6 +56359,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 cdbf5ba..7228ab9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -24810,11 +24810,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 {
@@ -25100,7 +25103,7 @@
     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 getUpdateIdentififer();
+    method public int getUpdateIdentifier();
     method public long getUsageLimitDataLimit();
     method public long getUsageLimitStartTimeInMs();
     method public long getUsageLimitTimeLimitInMinutes();
@@ -25142,7 +25145,7 @@
     method public int describeContents();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
-    method public boolean getCheckAaaServerStatus();
+    method public boolean getCheckAaaServerCertStatus();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
     method public long getCreationTimeInMs();
@@ -25223,7 +25226,7 @@
     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[] getMatchAnysOis();
+    method public long[] getMatchAnyOis();
     method public java.lang.String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(java.lang.String);
@@ -25245,7 +25248,7 @@
     method public int describeContents();
     method public java.lang.String[] getExcludedSsidList();
     method public int getMaximumBssLoadValue();
-    method public long getMinHomeDownlinkBandWidht();
+    method public long getMinHomeDownlinkBandwidth();
     method public long getMinHomeUplinkBandwidth();
     method public long getMinRoamingDownlinkBandwidth();
     method public long getMinRoamingUplinkBandwidth();
@@ -36660,9 +36663,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);
@@ -36674,9 +36679,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);
@@ -36703,6 +36711,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);
   }
@@ -36756,6 +36767,19 @@
     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 static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
@@ -37127,6 +37151,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
@@ -37339,6 +37364,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";
@@ -49358,6 +49384,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
@@ -50766,6 +50794,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;
@@ -52652,6 +52687,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);
@@ -52737,7 +52787,6 @@
     method public java.lang.Class<?> lookupClass();
     method public int lookupModes();
     method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
-    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
     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;
@@ -52780,6 +52829,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/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/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 82e3093..7c3e153 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1421,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);
@@ -1432,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);
         }
     }
 
@@ -2750,6 +2751,10 @@
             super(looper);
         }
 
+        CallbackHandler(Handler handler) {
+            this(handler.getLooper());
+        }
+
         @Override
         public void handleMessage(Message message) {
             NetworkRequest request = getObject(message, NetworkRequest.class);
@@ -2859,7 +2864,7 @@
         }
     }
 
-    private CallbackHandler getHandler() {
+    private CallbackHandler getDefaultHandler() {
         synchronized (sCallbacks) {
             if (sCallbackHandler == null) {
                 sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper());
@@ -2868,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");
         }
@@ -2924,8 +2924,18 @@
      */
     public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
             int timeoutMs, int legacyType) {
-        sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs, REQUEST,
-                legacyType);
+        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
+    }
+
+    /**
+     * Helper function to request a network with a particular legacy type.
+     * @hide
+     */
+    private void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+            int timeoutMs, int legacyType, Handler handler) {
+        CallbackHandler cbHandler = new CallbackHandler(handler);
+        NetworkCapabilities nc = request.networkCapabilities;
+        sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
     }
 
     /**
@@ -2951,15 +2961,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);
     }
 
     /**
@@ -2968,7 +3014,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);
+    }
+
+
+    /**
+     * 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
@@ -2977,30 +3052,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)}.
@@ -3111,9 +3178,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);
     }
 
     /**
@@ -3165,8 +3253,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.
         //
@@ -3174,7 +3279,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/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/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 b55dccf..1e0a998 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -44,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;
@@ -468,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 */
@@ -751,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/jni/Android.mk b/core/jni/Android.mk
index e940732..a9ca12b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -273,6 +273,7 @@
     libhidlbase \
     libhidltransport \
     libhwbinder \
+    libvintf \
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3580812..00d9a96 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -219,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();
 }
@@ -233,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));
 }
 
 // ----------------------------------------------------------------------
@@ -1274,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),
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 1f7efa1..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"
 
@@ -300,6 +301,8 @@
         jstring ifaceNameObj,
         jstring serviceNameObj) {
 
+    using ::android::vintf::operator<<;
+
     if (ifaceNameObj == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
         return NULL;
@@ -317,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_seccomp.cpp b/core/jni/android_os_seccomp.cpp
index 3f021ae..45d5061 100644
--- a/core/jni/android_os_seccomp.cpp
+++ b/core/jni/android_os_seccomp.cpp
@@ -148,7 +148,10 @@
     AllowSyscall(f, 128); // __NR_restart_syscall
 
     // b/35034743
-    AllowSyscall(f, 267); // __NR_fstatfs64
+    AllowSyscall(f, 267); // __NR_syncfs
+
+    // b/34763393
+    AllowSyscall(f, 277); // __NR_seccomp
 
     Trap(f);
 
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/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/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/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/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/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/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 252aaab..2dbec5e 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()) {
@@ -682,11 +683,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/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..bfb7041
--- /dev/null
+++ b/proto/src/wifi.proto
@@ -0,0 +1,443 @@
+/*
+ * 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 {
+  // Return code of the soft AP session
+  optional int32 return_code = 1;
+
+  // Occurences of this soft AP return code
+  optional int32 count = 2;
+}
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 00fe337..1feaa72 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22278,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 b0e4509..63e66a2 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1008,10 +1008,9 @@
                 return false;
             }
 
-            protected boolean requestUpstreamMobileConnection() {
+            protected void requestUpstreamMobileConnection() {
                 mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
                 mUpstreamNetworkMonitor.registerMobileNetworkRequest();
-                return true;
             }
 
             protected void unrequestUpstreamMobileConnection() {
@@ -1058,9 +1057,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?
 
@@ -1100,7 +1103,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);
@@ -1117,7 +1121,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) {
@@ -1359,9 +1369,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
@@ -1412,10 +1422,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 37221a9..5e51579 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -250,31 +250,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
@@ -306,6 +308,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 017c5fb..63024db 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -183,11 +183,31 @@
             case CALLBACK_LISTEN_ALL:
                 break;
             case CALLBACK_TRACK_DEFAULT:
+                if (mDefaultNetworkCallback == null) {
+                    // The callback was unregistered in the interval between
+                    // ConnectivityService calling onAvailable() and our
+                    // handling of it here on the mTarget.getHandler() thread.
+                    // Clean-up of this network entry is deferred to the
+                    // handling of onLost() by other callbacks.
+                    // TODO: change to Log.wtf() after oag/331764 is merged.
+                    return;
+                }
+
                 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 calling onAvailable() and our
+                    // handling of it here on the mTarget.getHandler() thread.
+                    // Clean-up of this network entry is deferred to the
+                    // handling of onLost() by other callbacks.
+                    // TODO: change to Log.wtf() after oag/331764 is merged.
+                    return;
+                }
+
                 cm().requestNetworkCapabilities(mMobileNetworkCallback);
                 cm().requestLinkProperties(mMobileNetworkCallback);
                 break;
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 c69b7c2..d67a0d6 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,142 @@
          * @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 {
+        @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;
+            }
+        }
     }
 
     /**
@@ -856,6 +1001,7 @@
     private String mCallingPackage;
     private String mRemainingPostDialSequence;
     private VideoCallImpl mVideoCallImpl;
+    private RttCall mRttCall;
     private Details mDetails;
     private Bundle mExtras;
 
@@ -1054,6 +1200,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>
@@ -1233,6 +1407,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}.
@@ -1426,6 +1617,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.
 
@@ -1447,6 +1664,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
@@ -1477,6 +1700,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;
@@ -1645,6 +1877,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 b7391b4..3e690b9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -31,10 +31,14 @@
 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;
@@ -385,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
     //**********************************************************************************************
 
     /**
@@ -757,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
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/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 5d68aae..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()) {
@@ -133,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;
             }
@@ -198,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() {
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index a3fce9c..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;
@@ -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/telecomm/java/android/telecom/ParcelableRttCall.aidl b/telecomm/java/android/telecom/ParcelableRttCall.aidl
new file mode 100644
index 0000000..4480710
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableRttCall.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+/**
+ * {@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 30ec5b3..ebd04c7 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -201,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/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 0c7404a..60a40f5 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -450,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 96070b8..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
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/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/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 32f487b..dd03305 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;
 
@@ -228,6 +220,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 +351,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 +536,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 +667,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..ddf5230 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>
@@ -5190,6 +5333,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 +6025,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..fe8dbfb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -0,0 +1,430 @@
+/*
+ * 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.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;
+
+/**
+ * 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) {
+                onCreateImsFeatureInternal(slotId, feature, c);
+            }
+        }
+
+        @Override
+        public void removeImsFeature(int slotId, int feature) throws RemoteException {
+            synchronized (mFeatures) {
+                onRemoveImsFeatureInternal(slotId, feature);
+            }
+        }
+
+        @Override
+        public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
+                IImsRegistrationListener listener) throws RemoteException {
+            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) {
+                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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            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 {
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.turnOnIms();
+                }
+            }
+        }
+
+        @Override
+        public void turnOffIms(int slotId, int featureType) throws RemoteException {
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.turnOffIms();
+                }
+            }
+        }
+
+        @Override
+        public IImsEcbm getEcbmInterface(int slotId, int featureType)
+                throws RemoteException {
+            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 {
+            synchronized (mFeatures) {
+                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+                if (feature != null) {
+                    feature.setUiTTYMode(uiTtyMode, onComplete);
+                }
+            }
+        }
+
+        @Override
+        public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
+                throws RemoteException {
+            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.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;
+    }
+
+    /**
+     * @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..8d7d260 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -16,18 +16,112 @@
 
 package android.telephony.ims.feature;
 
+import android.annotation.IntDef;
+import android.os.RemoteException;
+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";
 
     // 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;
+
+    public interface INotifyFeatureRemoved {
+        void onFeatureRemoved(int 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());
+            }
+        }
+    }
+
+    /**
+     * 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/com/android/ims/internal/IImsFeatureStatusCallback.aidl b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
new file mode 100644
index 0000000..41b1042
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+/**
+*  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..82a13dc 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
@@ -17,9 +17,11 @@
 package com.android.ims.internal;
 
 /**
+*  Interface from ImsResolver to ImsServiceProxy in ImsManager.
  * {@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/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 b770b19..81ecdc9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -411,6 +411,7 @@
     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;
 
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/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/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/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/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/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/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/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7b73b4b..1f661c4 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -120,7 +120,7 @@
     public void setUpdateIdentifier(int updateIdentifier) {
         mUpdateIdentifier = updateIdentifier;
     }
-    public int getUpdateIdentififer() {
+    public int getUpdateIdentifier() {
         return mUpdateIdentifier;
     }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 025d4d3..620759d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -100,7 +100,7 @@
     public void setCheckAaaServerCertStatus(boolean checkAaaServerCertStatus) {
         mCheckAaaServerCertStatus = checkAaaServerCertStatus;
     }
-    public boolean getCheckAaaServerStatus() {
+    public boolean getCheckAaaServerCertStatus() {
         return mCheckAaaServerCertStatus;
     }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 7a46129..8ec40c0 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -131,7 +131,7 @@
     public void setMatchAnyOis(long[] matchAnyOis) {
         mMatchAnyOis = matchAnyOis;
     }
-    public long[] getMatchAnysOis() {
+    public long[] getMatchAnyOis() {
         return mMatchAnyOis;
     }
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
index caca0e4..63238e8 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -77,7 +77,7 @@
     public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
         mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
     }
-    public long getMinHomeDownlinkBandWidht() {
+    public long getMinHomeDownlinkBandwidth() {
         return mMinHomeDownlinkBandwidth;
     }
     private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
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();