Merge "add injectSmsPdu with subId to ISms.aidl" into m-wireless-dev
diff --git a/Android.mk b/Android.mk
index 81113f7..8acd396 100644
--- a/Android.mk
+++ b/Android.mk
@@ -111,6 +111,7 @@
 	core/java/android/bluetooth/IBluetoothManagerCallback.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
 	core/java/android/bluetooth/IBluetoothMap.aidl \
+	core/java/android/bluetooth/IBluetoothSap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
 	core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
 	core/java/android/bluetooth/IBluetoothGatt.aidl \
@@ -205,6 +206,7 @@
 	core/java/android/os/IUpdateLock.aidl \
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
+	core/java/android/service/carrier/ICarrierConfigService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
@@ -373,15 +375,16 @@
 	telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl \
 	telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl \
 	telephony/java/com/android/ims/ImsConfigListener.aidl \
+	telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl \
+	telephony/java/com/android/internal/telephony/IMms.aidl \
+	telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
+	telephony/java/com/android/internal/telephony/ISms.aidl \
+	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
-	telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl \
-	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
-	telephony/java/com/android/internal/telephony/ISub.aidl \
-	telephony/java/com/android/internal/telephony/IMms.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
@@ -528,6 +531,7 @@
 	frameworks/base/core/java/android/view/textservice/SpellCheckerInfo.aidl \
 	frameworks/base/core/java/android/view/textservice/SentenceSuggestionsInfo.aidl \
 	frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
+	frameworks/base/core/java/android/service/carrier/CarrierIdentifier.aidl \
 	frameworks/base/core/java/android/service/carrier/MessagePdu.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
diff --git a/api/current.txt b/api/current.txt
index 98b15c7..ae21bb9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_CARRIER_CONFIG_SERVICE = "android.permission.BIND_CARRIER_CONFIG_SERVICE";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
@@ -6485,6 +6486,7 @@
     field public static final int GATT_SERVER = 8; // 0x8
     field public static final int HEADSET = 1; // 0x1
     field public static final int HEALTH = 3; // 0x3
+    field public static final int SAP = 10; // 0xa
     field public static final int STATE_CONNECTED = 2; // 0x2
     field public static final int STATE_CONNECTING = 1; // 0x1
     field public static final int STATE_DISCONNECTED = 0; // 0x0
@@ -6496,6 +6498,25 @@
     method public abstract void onServiceDisconnected(int);
   }
 
+  public final class BluetoothSap implements android.bluetooth.BluetoothProfile {
+    method public synchronized void close();
+    method public boolean connect(android.bluetooth.BluetoothDevice);
+    method public boolean disconnect(android.bluetooth.BluetoothDevice);
+    method public android.bluetooth.BluetoothDevice getClient();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public int getPriority(android.bluetooth.BluetoothDevice);
+    method public int getState();
+    method public boolean isConnected(android.bluetooth.BluetoothDevice);
+    method public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+    field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
+    field public static final int RESULT_CANCELED = 2; // 0x2
+    field public static final int RESULT_FAILURE = 0; // 0x0
+    field public static final int RESULT_SUCCESS = 1; // 0x1
+    field public static final int STATE_ERROR = -1; // 0xffffffff
+  }
+
   public final class BluetoothServerSocket implements java.io.Closeable {
     method public android.bluetooth.BluetoothSocket accept() throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket accept(int) throws java.io.IOException;
@@ -6505,10 +6526,16 @@
   public final class BluetoothSocket implements java.io.Closeable {
     method public void close() throws java.io.IOException;
     method public void connect() throws java.io.IOException;
+    method public int getConnectionType();
     method public java.io.InputStream getInputStream() throws java.io.IOException;
+    method public int getMaxReceivePacketSize();
+    method public int getMaxTransmitPacketSize();
     method public java.io.OutputStream getOutputStream() throws java.io.IOException;
     method public android.bluetooth.BluetoothDevice getRemoteDevice();
     method public boolean isConnected();
+    field public static final int TYPE_L2CAP = 3; // 0x3
+    field public static final int TYPE_RFCOMM = 1; // 0x1
+    field public static final int TYPE_SCO = 2; // 0x2
   }
 
 }
@@ -6658,7 +6685,14 @@
     method public int getScanResultType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CALLBACK_TYPE_ALL_MATCHES = 1; // 0x1
+    field public static final int CALLBACK_TYPE_FIRST_MATCH = 2; // 0x2
+    field public static final int CALLBACK_TYPE_MATCH_LOST = 4; // 0x4
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanSettings> CREATOR;
+    field public static final int MATCH_MODE_AGGRESSIVE = 1; // 0x1
+    field public static final int MATCH_MODE_STICKY = 2; // 0x2
+    field public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; // 0x2
+    field public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; // 0x3
+    field public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; // 0x1
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
@@ -6668,6 +6702,8 @@
   public static final class ScanSettings.Builder {
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
+    method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
+    method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
     method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
   }
@@ -7237,6 +7273,7 @@
     field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
     field public static final java.lang.String CAMERA_SERVICE = "camera";
     field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
+    field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
@@ -16954,34 +16991,43 @@
 
   public class ConnectivityManager {
     method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+    method public boolean bindProcessToNetwork(android.net.Network);
+    method public android.net.Network getActiveNetwork();
     method public android.net.NetworkInfo getActiveNetworkInfo();
-    method public android.net.NetworkInfo[] getAllNetworkInfo();
+    method public deprecated android.net.NetworkInfo[] getAllNetworkInfo();
     method public android.net.Network[] getAllNetworks();
     method public deprecated boolean getBackgroundDataSetting();
+    method public android.net.Network getBoundNetworkForProcess();
+    method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
-    method public android.net.NetworkInfo getNetworkInfo(int);
+    method public deprecated android.net.NetworkInfo getNetworkInfo(int);
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
     method public deprecated int getNetworkPreference();
-    method public static android.net.Network getProcessDefaultNetwork();
+    method public static deprecated android.net.Network getProcessDefaultNetwork();
+    method public void ignoreNetworkWithCaptivePortal(android.net.Network, java.lang.String);
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static boolean isNetworkTypeValid(int);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void releaseNetworkRequest(android.app.PendingIntent);
     method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public void reportBadNetwork(android.net.Network);
+    method public deprecated void reportBadNetwork(android.net.Network);
+    method public void reportCaptivePortalDismissed(android.net.Network, java.lang.String);
+    method public void reportNetworkConnectivity(android.net.Network, boolean);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
-    method public static boolean setProcessDefaultNetwork(android.net.Network);
+    method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
     method public deprecated int startUsingNetworkFeature(int, java.lang.String);
     method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+    field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_TOKEN = "captivePortalToken";
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
@@ -17142,8 +17188,10 @@
     method public int describeContents();
     method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
     method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
+    method public long getNetworkHandle();
     method public javax.net.SocketFactory getSocketFactory();
     method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
+    method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
   }
@@ -17253,7 +17301,7 @@
     method public static final deprecated int getDefaultPort();
     method public static final deprecated java.lang.String getHost(android.content.Context);
     method public static final deprecated int getPort(android.content.Context);
-    field public static final java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+    field public static final deprecated java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
     field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
@@ -17964,8 +18012,6 @@
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
-    field public int apBand;
-    field public int apChannel;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
     field public int networkId;
@@ -18034,6 +18080,7 @@
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public java.security.cert.X509Certificate getClientCertificate();
+    method public java.lang.String getDomainSubjectMatch();
     method public int getEapMethod();
     method public java.lang.String getIdentity();
     method public java.lang.String getPassword();
@@ -18045,6 +18092,7 @@
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+    method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
     method public void setIdentity(java.lang.String);
     method public void setPassword(java.lang.String);
@@ -25337,6 +25385,7 @@
     field public static final java.lang.String DEBUG_APP = "debug_app";
     field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
+    field public static final java.lang.String HIDE_CARRIER_NETWORK_SETTINGS = "hide_carrier_network_settings";
     field public static final java.lang.String HTTP_PROXY = "http_proxy";
     field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String MODE_RINGER = "mode_ringer";
@@ -25503,6 +25552,7 @@
     field public static final android.net.Uri DEFAULT_RINGTONE_URI;
     field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
     field public static final deprecated java.lang.String DIM_SCREEN = "dim_screen";
+    field public static final java.lang.String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
     field public static final java.lang.String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
     field public static final java.lang.String END_BUTTON_BEHAVIOR = "end_button_behavior";
     field public static final java.lang.String FONT_SCALE = "font_scale";
@@ -25551,6 +25601,7 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
+    field public static final java.lang.String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
     field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
     field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
     field public static final java.lang.String VOLUME_MUSIC = "volume_music";
@@ -25930,7 +25981,6 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -25954,9 +26004,6 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static int deleteAll(android.content.Context);
-    method public static android.net.Uri insert(android.content.Context, android.telecom.Voicemail);
-    method public static int insert(android.content.Context, java.util.List<android.telecom.Voicemail>);
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -26987,18 +27034,42 @@
 
 package android.service.carrier {
 
+  public abstract class CarrierConfigService extends android.app.Service {
+    ctor public CarrierConfigService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.os.Bundle onLoadConfig(android.service.carrier.CarrierIdentifier);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierConfigService";
+  }
+
+  public class CarrierIdentifier implements android.os.Parcelable {
+    ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public int describeContents();
+    method public java.lang.String getGid1();
+    method public java.lang.String getGid2();
+    method public java.lang.String getImsi();
+    method public java.lang.String getMcc();
+    method public java.lang.String getMnc();
+    method public java.lang.String getSpn();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.carrier.CarrierIdentifier> CREATOR;
+  }
+
   public abstract class CarrierMessagingService extends android.app.Service {
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
-    method public void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
-    method public void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
-    method public void onSendTextSms(java.lang.String, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public deprecated void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
+    method public void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
+    method public deprecated void onSendTextSms(java.lang.String, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendTextSms(java.lang.String, int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
     field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
@@ -28244,20 +28315,383 @@
 
 package android.telecom {
 
-  public class AuthenticatorService extends android.app.Service {
-    ctor public AuthenticatorService();
-    method public android.os.IBinder onBind(android.content.Intent);
+  public final class AudioState implements android.os.Parcelable {
+    ctor public AudioState(boolean, int, int);
+    ctor public AudioState(android.telecom.AudioState);
+    method public static java.lang.String audioRouteToString(int);
+    method public int describeContents();
+    method public int getRoute();
+    method public int getSupportedRouteMask();
+    method public boolean isMuted();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.AudioState> CREATOR;
+    field public static final int ROUTE_BLUETOOTH = 2; // 0x2
+    field public static final int ROUTE_EARPIECE = 1; // 0x1
+    field public static final int ROUTE_SPEAKER = 8; // 0x8
+    field public static final int ROUTE_WIRED_HEADSET = 4; // 0x4
+    field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
-  public class AuthenticatorService.Authenticator extends android.accounts.AbstractAccountAuthenticator {
-    ctor public AuthenticatorService.Authenticator(android.content.Context);
-    method public android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public java.lang.String getAuthTokenLabel(java.lang.String);
-    method public android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+  public final class Call {
+    method public void answer(int);
+    method public void conference(android.telecom.Call);
+    method public void disconnect();
+    method public java.util.List<java.lang.String> getCannedTextResponses();
+    method public java.util.List<android.telecom.Call> getChildren();
+    method public java.util.List<android.telecom.Call> getConferenceableCalls();
+    method public android.telecom.Call.Details getDetails();
+    method public android.telecom.Call getParent();
+    method public java.lang.String getRemainingPostDialSequence();
+    method public int getState();
+    method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void hold();
+    method public void mergeConference();
+    method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
+    method public void playDtmfTone(char);
+    method public void postDialContinue(boolean);
+    method public void registerCallback(android.telecom.Call.Callback);
+    method public void reject(boolean, java.lang.String);
+    method public void splitFromConference();
+    method public void stopDtmfTone();
+    method public void swapConference();
+    method public void unhold();
+    method public void unregisterCallback(android.telecom.Call.Callback);
+    field public static final java.lang.String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final int STATE_ACTIVE = 4; // 0x4
+    field public static final int STATE_CONNECTING = 9; // 0x9
+    field public static final int STATE_DIALING = 1; // 0x1
+    field public static final int STATE_DISCONNECTED = 7; // 0x7
+    field public static final int STATE_DISCONNECTING = 10; // 0xa
+    field public static final int STATE_HOLDING = 3; // 0x3
+    field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_PRE_DIAL_WAIT = 8; // 0x8
+    field public static final int STATE_RINGING = 2; // 0x2
+  }
+
+  public static abstract class Call.Callback {
+    ctor public Call.Callback();
+    method public void onCallDestroyed(android.telecom.Call);
+    method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
+    method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    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 onStateChanged(android.telecom.Call, int);
+    method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+  }
+
+  public static class Call.Details {
+    method public static boolean can(int, int);
+    method public boolean can(int);
+    method public static java.lang.String capabilitiesToString(int);
+    method public android.telecom.PhoneAccountHandle getAccountHandle();
+    method public int getCallCapabilities();
+    method public int getCallProperties();
+    method public java.lang.String getCallerDisplayName();
+    method public int getCallerDisplayNamePresentation();
+    method public final long getConnectTimeMillis();
+    method public android.telecom.DisconnectCause getDisconnectCause();
+    method public android.os.Bundle getExtras();
+    method public android.telecom.GatewayInfo getGatewayInfo();
+    method public android.net.Uri getHandle();
+    method public int getHandlePresentation();
+    method public android.telecom.StatusHints getStatusHints();
+    method public int getVideoState();
+    field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
+    field public static final int CAPABILITY_GENERIC_CONFERENCE = 16384; // 0x4000
+    field public static final int CAPABILITY_HIGH_DEF_AUDIO = 32768; // 0x8000
+    field public static final int CAPABILITY_HOLD = 1; // 0x1
+    field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
+    field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
+    field public static final int CAPABILITY_MUTE = 64; // 0x40
+    field public static final int CAPABILITY_RESPOND_VIA_TEXT = 32; // 0x20
+    field public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
+    field public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 131072; // 0x20000
+    field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 768; // 0x300
+    field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 256; // 0x100
+    field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 512; // 0x200
+    field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 3072; // 0xc00
+    field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 1024; // 0x400
+    field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
+    field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
+    field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final int CAPABILITY_WIFI = 65536; // 0x10000
+  }
+
+  public class CallProperties {
+    ctor public CallProperties();
+    field public static final int CONFERENCE = 1; // 0x1
+  }
+
+  public final class CallState {
+    method public static java.lang.String toString(int);
+    field public static final int ABORTED = 8; // 0x8
+    field public static final int ACTIVE = 5; // 0x5
+    field public static final int CONNECTING = 1; // 0x1
+    field public static final int DIALING = 3; // 0x3
+    field public static final int DISCONNECTED = 7; // 0x7
+    field public static final int DISCONNECTING = 9; // 0x9
+    field public static final int NEW = 0; // 0x0
+    field public static final int ON_HOLD = 6; // 0x6
+    field public static final int PRE_DIAL_WAIT = 2; // 0x2
+    field public static final int RINGING = 4; // 0x4
+  }
+
+  public final class CameraCapabilities implements android.os.Parcelable {
+    ctor public CameraCapabilities(int, int);
+    method public int describeContents();
+    method public int getHeight();
+    method public int getWidth();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.CameraCapabilities> CREATOR;
+  }
+
+  public abstract class Conference implements android.telecom.IConferenceable {
+    ctor public Conference(android.telecom.PhoneAccountHandle);
+    method public final boolean addConnection(android.telecom.Connection);
+    method public final void destroy();
+    method public final android.telecom.AudioState getAudioState();
+    method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
+    method public final long getConnectTimeMillis();
+    method public final int getConnectionCapabilities();
+    method public final java.util.List<android.telecom.Connection> getConnections();
+    method public final android.telecom.DisconnectCause getDisconnectCause();
+    method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method public android.telecom.Connection getPrimaryConnection();
+    method public final int getState();
+    method public final android.telecom.StatusHints getStatusHints();
+    method public void onAudioStateChanged(android.telecom.AudioState);
+    method public void onConnectionAdded(android.telecom.Connection);
+    method public void onDisconnect();
+    method public void onHold();
+    method public void onMerge(android.telecom.Connection);
+    method public void onMerge();
+    method public void onPlayDtmfTone(char);
+    method public void onSeparate(android.telecom.Connection);
+    method public void onStopDtmfTone();
+    method public void onSwap();
+    method public void onUnhold();
+    method public final void removeConnection(android.telecom.Connection);
+    method public final void setActive();
+    method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
+    method public void setConnectTimeMillis(long);
+    method public final void setConnectionCapabilities(int);
+    method public final void setDisconnected(android.telecom.DisconnectCause);
+    method public final void setOnHold();
+    method public final void setStatusHints(android.telecom.StatusHints);
+    field public static final long CONNECT_TIME_NOT_SPECIFIED = 0L; // 0x0L
+  }
+
+  public abstract class Connection implements android.telecom.IConferenceable {
+    ctor public Connection();
+    method public static java.lang.String capabilitiesToString(int);
+    method public static android.telecom.Connection createCanceledConnection();
+    method public static android.telecom.Connection createFailedConnection(android.telecom.DisconnectCause);
+    method public final void destroy();
+    method public final android.net.Uri getAddress();
+    method public final int getAddressPresentation();
+    method public final boolean getAudioModeIsVoip();
+    method public final android.telecom.AudioState getAudioState();
+    method public final java.lang.String getCallerDisplayName();
+    method public final int getCallerDisplayNamePresentation();
+    method public final android.telecom.Conference getConference();
+    method public final java.util.List<android.telecom.IConferenceable> getConferenceables();
+    method public final int getConnectionCapabilities();
+    method public final android.telecom.DisconnectCause getDisconnectCause();
+    method public final int getState();
+    method public final android.telecom.StatusHints getStatusHints();
+    method public final android.telecom.Connection.VideoProvider getVideoProvider();
+    method public final boolean isRingbackRequested();
+    method public void onAbort();
+    method public void onAnswer();
+    method public void onAudioStateChanged(android.telecom.AudioState);
+    method public void onDisconnect();
+    method public void onHold();
+    method public void onPlayDtmfTone(char);
+    method public void onPostDialContinue(boolean);
+    method public void onReject();
+    method public void onSeparate();
+    method public void onStateChanged(int);
+    method public void onStopDtmfTone();
+    method public void onUnhold();
+    method public final void setActive();
+    method public final void setAddress(android.net.Uri, int);
+    method public final void setAudioModeIsVoip(boolean);
+    method public final void setCallerDisplayName(java.lang.String, int);
+    method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
+    method public final void setConferenceables(java.util.List<android.telecom.IConferenceable>);
+    method public final void setConnectionCapabilities(int);
+    method public final void setConnectionService(android.telecom.ConnectionService);
+    method public final void setDialing();
+    method public final void setDisconnected(android.telecom.DisconnectCause);
+    method public final void setInitialized();
+    method public final void setInitializing();
+    method public final void setOnHold();
+    method public final void setPostDialWait(java.lang.String);
+    method public final void setRingbackRequested(boolean);
+    method public final void setRinging();
+    method public final void setStatusHints(android.telecom.StatusHints);
+    method public static java.lang.String stateToString(int);
+    field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
+    field public static final int CAPABILITY_HOLD = 1; // 0x1
+    field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
+    field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
+    field public static final int CAPABILITY_MUTE = 64; // 0x40
+    field public static final int CAPABILITY_RESPOND_VIA_TEXT = 32; // 0x20
+    field public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
+    field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
+    field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final int STATE_ACTIVE = 4; // 0x4
+    field public static final int STATE_DIALING = 3; // 0x3
+    field public static final int STATE_DISCONNECTED = 6; // 0x6
+    field public static final int STATE_HOLDING = 5; // 0x5
+    field public static final int STATE_INITIALIZING = 0; // 0x0
+    field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_RINGING = 2; // 0x2
+  }
+
+  public static abstract class Connection.VideoProvider {
+    ctor public Connection.VideoProvider();
+    method public void changeCallDataUsage(long);
+    method public void changeCameraCapabilities(android.telecom.CameraCapabilities);
+    method public void changePeerDimensions(int, int);
+    method public void changeVideoQuality(int);
+    method public void handleCallSessionEvent(int);
+    method public abstract void onRequestCameraCapabilities();
+    method public abstract void onRequestConnectionDataUsage();
+    method public abstract void onSendSessionModifyRequest(android.telecom.VideoProfile);
+    method public abstract void onSendSessionModifyResponse(android.telecom.VideoProfile);
+    method public abstract void onSetCamera(java.lang.String);
+    method public abstract void onSetDeviceOrientation(int);
+    method public abstract void onSetDisplaySurface(android.view.Surface);
+    method public abstract void onSetPauseImage(java.lang.String);
+    method public abstract void onSetPreviewSurface(android.view.Surface);
+    method public abstract void onSetZoom(float);
+    method public void receiveSessionModifyRequest(android.telecom.VideoProfile);
+    method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
+    field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
+    field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
+    field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
+    field public static final int SESSION_EVENT_TX_START = 3; // 0x3
+    field public static final int SESSION_EVENT_TX_STOP = 4; // 0x4
+    field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
+    field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
+    field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
+    field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
+    field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
+  }
+
+  public final class ConnectionRequest implements android.os.Parcelable {
+    ctor public ConnectionRequest(android.telecom.PhoneAccountHandle, android.net.Uri, android.os.Bundle);
+    method public int describeContents();
+    method public android.telecom.PhoneAccountHandle getAccountHandle();
+    method public android.net.Uri getAddress();
+    method public android.os.Bundle getExtras();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR;
+  }
+
+  public abstract class ConnectionService extends android.app.Service {
+    ctor public ConnectionService();
+    method public final void addConference(android.telecom.Conference);
+    method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection);
+    method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
+    method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public final java.util.Collection<android.telecom.Connection> getAllConnections();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onConference(android.telecom.Connection, android.telecom.Connection);
+    method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
+    method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
+  }
+
+  public final class DisconnectCause implements android.os.Parcelable {
+    ctor public DisconnectCause(int);
+    ctor public DisconnectCause(int, java.lang.String);
+    ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String);
+    ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String, int);
+    method public int describeContents();
+    method public int getCode();
+    method public java.lang.CharSequence getDescription();
+    method public java.lang.CharSequence getLabel();
+    method public java.lang.String getReason();
+    method public int getTone();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int BUSY = 7; // 0x7
+    field public static final int CANCELED = 4; // 0x4
+    field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
+    field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
+    field public static final int ERROR = 1; // 0x1
+    field public static final int LOCAL = 2; // 0x2
+    field public static final int MISSED = 5; // 0x5
+    field public static final int OTHER = 9; // 0x9
+    field public static final int REJECTED = 6; // 0x6
+    field public static final int REMOTE = 3; // 0x3
+    field public static final int RESTRICTED = 8; // 0x8
+    field public static final int UNKNOWN = 0; // 0x0
+  }
+
+  public class GatewayInfo implements android.os.Parcelable {
+    ctor public GatewayInfo(java.lang.String, android.net.Uri, android.net.Uri);
+    method public int describeContents();
+    method public android.net.Uri getGatewayAddress();
+    method public java.lang.String getGatewayProviderPackageName();
+    method public android.net.Uri getOriginalAddress();
+    method public boolean isEmpty();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.GatewayInfo> CREATOR;
+  }
+
+  public abstract interface IConferenceable {
+  }
+
+  public abstract class InCallService extends android.app.Service {
+    ctor public InCallService();
+    method public final boolean canAddCall();
+    method public final android.telecom.AudioState getAudioState();
+    method public final java.util.List<android.telecom.Call> getCalls();
+    method public void onAudioStateChanged(android.telecom.AudioState);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onBringToForeground(boolean);
+    method public void onCallAdded(android.telecom.Call);
+    method public void onCallRemoved(android.telecom.Call);
+    method public void onCanAddCallChanged(boolean);
+    method public final void setAudioRoute(int);
+    method public final void setMuted(boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
+  }
+
+  public static abstract class InCallService.VideoCall {
+    ctor public InCallService.VideoCall();
+    method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback);
+    method public abstract void requestCallDataUsage();
+    method public abstract void requestCameraCapabilities();
+    method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile);
+    method public abstract void sendSessionModifyResponse(android.telecom.VideoProfile);
+    method public abstract void setCamera(java.lang.String);
+    method public abstract void setDeviceOrientation(int);
+    method public abstract void setDisplaySurface(android.view.Surface);
+    method public abstract void setPauseImage(java.lang.String);
+    method public abstract void setPreviewSurface(android.view.Surface);
+    method public abstract void setZoom(float);
+    method public abstract void unregisterCallback();
+  }
+
+  public static abstract class InCallService.VideoCall.Callback {
+    ctor public InCallService.VideoCall.Callback();
+    method public abstract void onCallDataUsageChanged(long);
+    method public abstract void onCallSessionEvent(int);
+    method public abstract void onCameraCapabilitiesChanged(android.telecom.CameraCapabilities);
+    method public abstract void onPeerDimensionsChanged(int, int);
+    method public abstract void onSessionModifyRequestReceived(android.telecom.VideoProfile);
+    method public abstract void onSessionModifyResponseReceived(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
+    method public abstract void onVideoQualityChanged(int);
   }
 
   public class PhoneAccount implements android.os.Parcelable {
@@ -28278,9 +28712,13 @@
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
     method public boolean supportsUriScheme(java.lang.String);
+    method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
+    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_SIM_SUBSCRIPTION = 4; // 0x4
+    field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_ICON_TINT = 0; // 0x0
@@ -28293,6 +28731,7 @@
   public static class PhoneAccount.Builder {
     ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
     ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
+    method public android.telecom.PhoneAccount.Builder addSupportedUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount build();
     method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
     method public android.telecom.PhoneAccount.Builder setCapabilities(int);
@@ -28309,24 +28748,128 @@
 
   public class PhoneAccountHandle implements android.os.Parcelable {
     ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
+    ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String, android.os.UserHandle);
     method public int describeContents();
     method public android.content.ComponentName getComponentName();
     method public java.lang.String getId();
+    method public android.os.UserHandle getUserHandle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR;
   }
 
+  public final class RemoteConference {
+    method public void disconnect();
+    method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
+    method public final int getConnectionCapabilities();
+    method public final java.util.List<android.telecom.RemoteConnection> getConnections();
+    method public android.telecom.DisconnectCause getDisconnectCause();
+    method public final int getState();
+    method public void hold();
+    method public void merge();
+    method public void playDtmfTone(char);
+    method public final void registerCallback(android.telecom.RemoteConference.Callback);
+    method public void separate(android.telecom.RemoteConnection);
+    method public void setAudioState(android.telecom.AudioState);
+    method public void stopDtmfTone();
+    method public void swap();
+    method public void unhold();
+    method public final void unregisterCallback(android.telecom.RemoteConference.Callback);
+  }
+
+  public static abstract class RemoteConference.Callback {
+    ctor public RemoteConference.Callback();
+    method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
+    method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
+    method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
+    method public void onDestroyed(android.telecom.RemoteConference);
+    method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
+    method public void onStateChanged(android.telecom.RemoteConference, int, int);
+  }
+
+  public final class RemoteConnection {
+    method public void abort();
+    method public void answer();
+    method public void disconnect();
+    method public android.net.Uri getAddress();
+    method public int getAddressPresentation();
+    method public java.lang.CharSequence getCallerDisplayName();
+    method public int getCallerDisplayNamePresentation();
+    method public android.telecom.RemoteConference getConference();
+    method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
+    method public int getConnectionCapabilities();
+    method public android.telecom.DisconnectCause getDisconnectCause();
+    method public int getState();
+    method public android.telecom.StatusHints getStatusHints();
+    method public void hold();
+    method public boolean isRingbackRequested();
+    method public boolean isVoipAudioMode();
+    method public void playDtmfTone(char);
+    method public void postDialContinue(boolean);
+    method public void registerCallback(android.telecom.RemoteConnection.Callback);
+    method public void reject();
+    method public void setAudioState(android.telecom.AudioState);
+    method public void stopDtmfTone();
+    method public void unhold();
+    method public void unregisterCallback(android.telecom.RemoteConnection.Callback);
+  }
+
+  public static abstract class RemoteConnection.Callback {
+    ctor public RemoteConnection.Callback();
+    method public void onAddressChanged(android.telecom.RemoteConnection, android.net.Uri, int);
+    method public void onCallerDisplayNameChanged(android.telecom.RemoteConnection, java.lang.String, int);
+    method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
+    method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
+    method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onDestroyed(android.telecom.RemoteConnection);
+    method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
+    method public void onPostDialChar(android.telecom.RemoteConnection, char);
+    method public void onPostDialWait(android.telecom.RemoteConnection, java.lang.String);
+    method public void onRingbackRequested(android.telecom.RemoteConnection, boolean);
+    method public void onStateChanged(android.telecom.RemoteConnection, int);
+    method public void onStatusHintsChanged(android.telecom.RemoteConnection, android.telecom.StatusHints);
+    method public void onVoipAudioChanged(android.telecom.RemoteConnection, boolean);
+  }
+
+  public final class StatusHints implements android.os.Parcelable {
+    ctor public StatusHints(android.content.ComponentName, java.lang.CharSequence, int, android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.drawable.Drawable getIcon(android.content.Context);
+    method public int getIconResId();
+    method public java.lang.CharSequence getLabel();
+    method public android.content.ComponentName getPackageName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.StatusHints> CREATOR;
+  }
+
   public class TelecomManager {
+    method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
+    method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
+    method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
+    method public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String);
+    method public java.lang.String getLine1Number(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
+    method public android.telecom.PhoneAccountHandle getSimCallManager();
+    method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
+    method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
+    method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
+    method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
+    method public void silenceRinger();
+    method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
+    field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
+    field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
+    field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
     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_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
@@ -28367,39 +28910,23 @@
     field public static final int TX_ENABLED = 1; // 0x1
   }
 
-  public class Voicemail implements android.os.Parcelable {
-    method public static android.telecom.Voicemail.Builder createForInsertion(long, java.lang.String);
-    method public int describeContents();
-    method public long getDuration();
-    method public long getId();
-    method public java.lang.String getNumber();
-    method public java.lang.String getSourceData();
-    method public java.lang.String getSourcePackage();
-    method public long getTimestampMillis();
-    method public android.net.Uri getUri();
-    method public boolean hasContent();
-    method public boolean isRead();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telecom.Voicemail> CREATOR;
-  }
-
-  public static class Voicemail.Builder {
-    method public android.telecom.Voicemail build();
-    method public android.telecom.Voicemail.Builder setDuration(long);
-    method public android.telecom.Voicemail.Builder setHasContent(boolean);
-    method public android.telecom.Voicemail.Builder setId(long);
-    method public android.telecom.Voicemail.Builder setIsRead(boolean);
-    method public android.telecom.Voicemail.Builder setNumber(java.lang.String);
-    method public android.telecom.Voicemail.Builder setSourceData(java.lang.String);
-    method public android.telecom.Voicemail.Builder setSourcePackage(java.lang.String);
-    method public android.telecom.Voicemail.Builder setTimestamp(long);
-    method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
-  }
-
 }
 
 package android.telephony {
 
+  public class CarrierConfigManager {
+    ctor public CarrierConfigManager();
+    method public android.os.Bundle getConfig();
+    method public android.os.Bundle getConfigForSubId(int);
+    method public void reloadCarrierConfigForSubId(int);
+    field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.intent.action.carrier_config_changed";
+    field public static final java.lang.String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
+    field public static final java.lang.String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
+    field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
+    field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
+  }
+
   public final class CellIdentityCdma implements android.os.Parcelable {
     method public int describeContents();
     method public int getBasestationId();
@@ -28771,7 +29298,8 @@
   public class SmsMessage {
     method public static int[] calculateLength(java.lang.CharSequence, boolean);
     method public static int[] calculateLength(java.lang.String, boolean);
-    method public static android.telephony.SmsMessage createFromPdu(byte[]);
+    method public static deprecated android.telephony.SmsMessage createFromPdu(byte[]);
+    method public static android.telephony.SmsMessage createFromPdu(byte[], java.lang.String);
     method public java.lang.String getDisplayMessageBody();
     method public java.lang.String getDisplayOriginatingAddress();
     method public java.lang.String getEmailBody();
@@ -28870,6 +29398,7 @@
     method public int getDataActivity();
     method public int getDataState();
     method public java.lang.String getDeviceId();
+    method public java.lang.String getDeviceId(int);
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getLine1Number();
@@ -28880,6 +29409,7 @@
     method public java.lang.String getNetworkOperator();
     method public java.lang.String getNetworkOperatorName();
     method public int getNetworkType();
+    method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
diff --git a/api/system-current.txt b/api/system-current.txt
index 6838ec1..582e7e4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -28,6 +28,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_CARRIER_CONFIG_SERVICE = "android.permission.BIND_CARRIER_CONFIG_SERVICE";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
     field public static final java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
@@ -6033,6 +6034,7 @@
     method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
     method public int getScanMode();
     method public int getState();
+    method public boolean isBleScanAlwaysAvailable();
     method public boolean isDiscovering();
     method public boolean isEnabled();
     method public boolean isMultipleAdvertisementSupported();
@@ -6049,6 +6051,7 @@
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
     field public static final java.lang.String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+    field public static final java.lang.String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
     field public static final java.lang.String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
     field public static final java.lang.String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
     field public static final java.lang.String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
@@ -6699,6 +6702,7 @@
     field public static final int GATT_SERVER = 8; // 0x8
     field public static final int HEADSET = 1; // 0x1
     field public static final int HEALTH = 3; // 0x3
+    field public static final int SAP = 10; // 0xa
     field public static final int STATE_CONNECTED = 2; // 0x2
     field public static final int STATE_CONNECTING = 1; // 0x1
     field public static final int STATE_DISCONNECTED = 0; // 0x0
@@ -6710,6 +6714,25 @@
     method public abstract void onServiceDisconnected(int);
   }
 
+  public final class BluetoothSap implements android.bluetooth.BluetoothProfile {
+    method public synchronized void close();
+    method public boolean connect(android.bluetooth.BluetoothDevice);
+    method public boolean disconnect(android.bluetooth.BluetoothDevice);
+    method public android.bluetooth.BluetoothDevice getClient();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public int getPriority(android.bluetooth.BluetoothDevice);
+    method public int getState();
+    method public boolean isConnected(android.bluetooth.BluetoothDevice);
+    method public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+    field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
+    field public static final int RESULT_CANCELED = 2; // 0x2
+    field public static final int RESULT_FAILURE = 0; // 0x0
+    field public static final int RESULT_SUCCESS = 1; // 0x1
+    field public static final int STATE_ERROR = -1; // 0xffffffff
+  }
+
   public final class BluetoothServerSocket implements java.io.Closeable {
     method public android.bluetooth.BluetoothSocket accept() throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket accept(int) throws java.io.IOException;
@@ -6719,10 +6742,16 @@
   public final class BluetoothSocket implements java.io.Closeable {
     method public void close() throws java.io.IOException;
     method public void connect() throws java.io.IOException;
+    method public int getConnectionType();
     method public java.io.InputStream getInputStream() throws java.io.IOException;
+    method public int getMaxReceivePacketSize();
+    method public int getMaxTransmitPacketSize();
     method public java.io.OutputStream getOutputStream() throws java.io.IOException;
     method public android.bluetooth.BluetoothDevice getRemoteDevice();
     method public boolean isConnected();
+    field public static final int TYPE_L2CAP = 3; // 0x3
+    field public static final int TYPE_RFCOMM = 1; // 0x1
+    field public static final int TYPE_SCO = 2; // 0x2
   }
 
 }
@@ -6886,6 +6915,11 @@
     field public static final int CALLBACK_TYPE_FIRST_MATCH = 2; // 0x2
     field public static final int CALLBACK_TYPE_MATCH_LOST = 4; // 0x4
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanSettings> CREATOR;
+    field public static final int MATCH_MODE_AGGRESSIVE = 1; // 0x1
+    field public static final int MATCH_MODE_STICKY = 2; // 0x2
+    field public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; // 0x2
+    field public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; // 0x3
+    field public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; // 0x1
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
@@ -6898,6 +6932,8 @@
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
     method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
+    method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
+    method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
     method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setScanResultType(int);
@@ -7476,6 +7512,7 @@
     field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
     field public static final java.lang.String CAMERA_SERVICE = "camera";
     field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
+    field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
@@ -18213,34 +18250,43 @@
 
   public class ConnectivityManager {
     method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+    method public boolean bindProcessToNetwork(android.net.Network);
+    method public android.net.Network getActiveNetwork();
     method public android.net.NetworkInfo getActiveNetworkInfo();
-    method public android.net.NetworkInfo[] getAllNetworkInfo();
+    method public deprecated android.net.NetworkInfo[] getAllNetworkInfo();
     method public android.net.Network[] getAllNetworks();
     method public deprecated boolean getBackgroundDataSetting();
+    method public android.net.Network getBoundNetworkForProcess();
+    method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
-    method public android.net.NetworkInfo getNetworkInfo(int);
+    method public deprecated android.net.NetworkInfo getNetworkInfo(int);
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
     method public deprecated int getNetworkPreference();
-    method public static android.net.Network getProcessDefaultNetwork();
+    method public static deprecated android.net.Network getProcessDefaultNetwork();
+    method public void ignoreNetworkWithCaptivePortal(android.net.Network, java.lang.String);
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static boolean isNetworkTypeValid(int);
     method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void releaseNetworkRequest(android.app.PendingIntent);
     method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public void reportBadNetwork(android.net.Network);
+    method public deprecated void reportBadNetwork(android.net.Network);
+    method public void reportCaptivePortalDismissed(android.net.Network, java.lang.String);
+    method public void reportNetworkConnectivity(android.net.Network, boolean);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
-    method public static boolean setProcessDefaultNetwork(android.net.Network);
+    method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
     method public deprecated int startUsingNetworkFeature(int, java.lang.String);
     method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+    field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_TOKEN = "captivePortalToken";
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
@@ -18401,8 +18447,10 @@
     method public int describeContents();
     method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
     method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
+    method public long getNetworkHandle();
     method public javax.net.SocketFactory getSocketFactory();
     method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
+    method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
   }
@@ -18537,7 +18585,7 @@
     method public static final deprecated int getDefaultPort();
     method public static final deprecated java.lang.String getHost(android.content.Context);
     method public static final deprecated int getPort(android.content.Context);
-    field public static final java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+    field public static final deprecated java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
     field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
@@ -19258,6 +19306,7 @@
     field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
     field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
     field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
+    field public static final int REASON_PERMISSION_DENIED = -5; // 0xfffffffb
     field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
     field public static final int RTT_BW_10_SUPPORT = 2; // 0x2
     field public static final int RTT_BW_160_SUPPORT = 32; // 0x20
@@ -19265,21 +19314,25 @@
     field public static final int RTT_BW_40_SUPPORT = 8; // 0x8
     field public static final int RTT_BW_5_SUPPORT = 1; // 0x1
     field public static final int RTT_BW_80_SUPPORT = 16; // 0x10
-    field public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
-    field public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
-    field public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
-    field public static final int RTT_CHANNEL_WIDTH_40 = 1; // 0x1
-    field public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
-    field public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
-    field public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
+    field public static final deprecated int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
+    field public static final deprecated int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
+    field public static final deprecated int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
+    field public static final deprecated int RTT_CHANNEL_WIDTH_40 = 1; // 0x1
+    field public static final deprecated int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
+    field public static final deprecated int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
+    field public static final deprecated int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
     field public static final deprecated int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+    field public static final int RTT_PEER_NAN = 5; // 0x5
+    field public static final int RTT_PEER_P2P_CLIENT = 4; // 0x4
+    field public static final int RTT_PEER_P2P_GO = 3; // 0x3
     field public static final int RTT_PEER_TYPE_AP = 1; // 0x1
     field public static final int RTT_PEER_TYPE_STA = 2; // 0x2
-    field public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
+    field public static final deprecated int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
     field public static final int RTT_STATUS_ABORTED = 8; // 0x8
     field public static final int RTT_STATUS_FAILURE = 1; // 0x1
     field public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
     field public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+    field public static final int RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15; // 0xf
     field public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
     field public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
     field public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
@@ -19288,11 +19341,13 @@
     field public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
     field public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
     field public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
+    field public static final int RTT_STATUS_INVALID_REQ = 13; // 0xd
+    field public static final int RTT_STATUS_NO_WIFI = 14; // 0xe
     field public static final int RTT_STATUS_SUCCESS = 0; // 0x0
     field public static final deprecated int RTT_TYPE_11_MC = 4; // 0x4
     field public static final deprecated int RTT_TYPE_11_V = 2; // 0x2
     field public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
-    field public static final int RTT_TYPE_TWO_SIDED = 4; // 0x4
+    field public static final int RTT_TYPE_TWO_SIDED = 2; // 0x2
     field public static final deprecated int RTT_TYPE_UNSPECIFIED = 0; // 0x0
   }
 
@@ -19360,6 +19415,8 @@
 
   public static class RttManager.RttResult {
     ctor public RttManager.RttResult();
+    field public android.net.wifi.RttManager.WifiInformationElement LCI;
+    field public android.net.wifi.RttManager.WifiInformationElement LCR;
     field public java.lang.String bssid;
     field public int burstDuration;
     field public int burstNumber;
@@ -19372,6 +19429,7 @@
     field public int frameNumberPerBurstPeer;
     field public int measurementFrameNumber;
     field public int measurementType;
+    field public int negotiatedBurstNum;
     field public deprecated int requestType;
     field public int retryAfterDuration;
     field public int rssi;
@@ -19391,10 +19449,10 @@
     field public deprecated int tx_rate;
   }
 
-  public class RttManager.wifiInformationElement {
-    ctor public RttManager.wifiInformationElement();
-    field public java.lang.String data;
-    field public int id;
+  public static class RttManager.WifiInformationElement {
+    ctor public RttManager.WifiInformationElement();
+    field public byte[] data;
+    field public byte id;
   }
 
   public class ScanResult implements android.os.Parcelable {
@@ -19454,8 +19512,6 @@
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
-    field public int apBand;
-    field public int apChannel;
     field public int creatorUid;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
@@ -19544,6 +19600,7 @@
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public java.security.cert.X509Certificate getClientCertificate();
+    method public java.lang.String getDomainSubjectMatch();
     method public int getEapMethod();
     method public java.lang.String getIdentity();
     method public java.lang.String getPassword();
@@ -19555,6 +19612,7 @@
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
+    method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
     method public void setIdentity(java.lang.String);
     method public void setPassword(java.lang.String);
@@ -27023,6 +27081,7 @@
     field public static final java.lang.String DEBUG_APP = "debug_app";
     field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
+    field public static final java.lang.String HIDE_CARRIER_NETWORK_SETTINGS = "hide_carrier_network_settings";
     field public static final java.lang.String HTTP_PROXY = "http_proxy";
     field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String MODE_RINGER = "mode_ringer";
@@ -27189,6 +27248,7 @@
     field public static final android.net.Uri DEFAULT_RINGTONE_URI;
     field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
     field public static final deprecated java.lang.String DIM_SCREEN = "dim_screen";
+    field public static final java.lang.String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
     field public static final java.lang.String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
     field public static final java.lang.String END_BUTTON_BEHAVIOR = "end_button_behavior";
     field public static final java.lang.String FONT_SCALE = "font_scale";
@@ -27237,6 +27297,7 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
+    field public static final java.lang.String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
     field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
     field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
     field public static final java.lang.String VOLUME_MUSIC = "volume_music";
@@ -27616,7 +27677,6 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -27640,9 +27700,6 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static int deleteAll(android.content.Context);
-    method public static android.net.Uri insert(android.content.Context, android.telecom.Voicemail);
-    method public static int insert(android.content.Context, java.util.List<android.telecom.Voicemail>);
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -28673,18 +28730,42 @@
 
 package android.service.carrier {
 
+  public abstract class CarrierConfigService extends android.app.Service {
+    ctor public CarrierConfigService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.os.Bundle onLoadConfig(android.service.carrier.CarrierIdentifier);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierConfigService";
+  }
+
+  public class CarrierIdentifier implements android.os.Parcelable {
+    ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public int describeContents();
+    method public java.lang.String getGid1();
+    method public java.lang.String getGid2();
+    method public java.lang.String getImsi();
+    method public java.lang.String getMcc();
+    method public java.lang.String getMnc();
+    method public java.lang.String getSpn();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.carrier.CarrierIdentifier> CREATOR;
+  }
+
   public abstract class CarrierMessagingService extends android.app.Service {
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
-    method public void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
-    method public void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
-    method public void onSendTextSms(java.lang.String, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public deprecated void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
+    method public void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
+    method public deprecated void onSendTextSms(java.lang.String, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendTextSms(java.lang.String, int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
     field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
@@ -30052,6 +30133,7 @@
   public final class AudioState implements android.os.Parcelable {
     ctor public AudioState(boolean, int, int);
     ctor public AudioState(android.telecom.AudioState);
+    method public static java.lang.String audioRouteToString(int);
     method public int describeContents();
     method public int getRoute();
     method public int getSupportedRouteMask();
@@ -30063,29 +30145,10 @@
     field public static final int ROUTE_SPEAKER = 8; // 0x8
     field public static final int ROUTE_WIRED_HEADSET = 4; // 0x4
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
-    field public final boolean isMuted;
-    field public final int route;
-    field public final int supportedRouteMask;
-  }
-
-  public class AuthenticatorService extends android.app.Service {
-    ctor public AuthenticatorService();
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
-  public class AuthenticatorService.Authenticator extends android.accounts.AbstractAccountAuthenticator {
-    ctor public AuthenticatorService.Authenticator(android.content.Context);
-    method public android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public java.lang.String getAuthTokenLabel(java.lang.String);
-    method public android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
   }
 
   public final class Call {
-    method public void addListener(android.telecom.Call.Listener);
+    method public deprecated void addListener(android.telecom.Call.Listener);
     method public void answer(int);
     method public void conference(android.telecom.Call);
     method public void disconnect();
@@ -30096,17 +30159,21 @@
     method public android.telecom.Call getParent();
     method public java.lang.String getRemainingPostDialSequence();
     method public int getState();
+    method public android.telecom.InCallService.VideoCall getVideoCall();
     method public void hold();
     method public void mergeConference();
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void registerCallback(android.telecom.Call.Callback);
     method public void reject(boolean, java.lang.String);
-    method public void removeListener(android.telecom.Call.Listener);
+    method public deprecated void removeListener(android.telecom.Call.Listener);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
     method public void unhold();
+    method public void unregisterCallback(android.telecom.Call.Callback);
+    field public static final java.lang.String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
@@ -30118,34 +30185,8 @@
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
-  public static class Call.Details {
-    method public static java.lang.String capabilitiesToString(int);
-    method public android.telecom.PhoneAccountHandle getAccountHandle();
-    method public int getCallCapabilities();
-    method public int getCallProperties();
-    method public java.lang.String getCallerDisplayName();
-    method public int getCallerDisplayNamePresentation();
-    method public long getConnectTimeMillis();
-    method public android.telecom.DisconnectCause getDisconnectCause();
-    method public android.os.Bundle getExtras();
-    method public android.telecom.GatewayInfo getGatewayInfo();
-    method public android.net.Uri getHandle();
-    method public int getHandlePresentation();
-    method public android.telecom.StatusHints getStatusHints();
-    method public int getVideoState();
-    field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
-    field public static final int CAPABILITY_HOLD = 1; // 0x1
-    field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
-    field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
-    field public static final int CAPABILITY_MUTE = 64; // 0x40
-    field public static final int CAPABILITY_RESPOND_VIA_TEXT = 32; // 0x20
-    field public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
-    field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
-    field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
-  }
-
-  public static abstract class Call.Listener {
-    ctor public Call.Listener();
+  public static abstract class Call.Callback {
+    ctor public Call.Callback();
     method public void onCallDestroyed(android.telecom.Call);
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
@@ -30154,6 +30195,55 @@
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onStateChanged(android.telecom.Call, int);
+    method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+  }
+
+  public static class Call.Details {
+    method public static boolean can(int, int);
+    method public boolean can(int);
+    method public static java.lang.String capabilitiesToString(int);
+    method public android.telecom.PhoneAccountHandle getAccountHandle();
+    method public int getCallCapabilities();
+    method public int getCallProperties();
+    method public java.lang.String getCallerDisplayName();
+    method public int getCallerDisplayNamePresentation();
+    method public final long getConnectTimeMillis();
+    method public android.telecom.DisconnectCause getDisconnectCause();
+    method public android.os.Bundle getExtras();
+    method public android.telecom.GatewayInfo getGatewayInfo();
+    method public android.net.Uri getHandle();
+    method public int getHandlePresentation();
+    method public android.telecom.StatusHints getStatusHints();
+    method public int getVideoState();
+    field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
+    field public static final int CAPABILITY_GENERIC_CONFERENCE = 16384; // 0x4000
+    field public static final int CAPABILITY_HIGH_DEF_AUDIO = 32768; // 0x8000
+    field public static final int CAPABILITY_HOLD = 1; // 0x1
+    field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
+    field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
+    field public static final int CAPABILITY_MUTE = 64; // 0x40
+    field public static final int CAPABILITY_RESPOND_VIA_TEXT = 32; // 0x20
+    field public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
+    field public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 131072; // 0x20000
+    field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 768; // 0x300
+    field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 256; // 0x100
+    field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 512; // 0x200
+    field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 3072; // 0xc00
+    field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 1024; // 0x400
+    field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
+    field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
+    field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final int CAPABILITY_WIFI = 65536; // 0x10000
+  }
+
+  public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
+    ctor public Call.Listener();
+  }
+
+  public class CallProperties {
+    ctor public CallProperties();
+    field public static final int CONFERENCE = 1; // 0x1
   }
 
   public final class CallState {
@@ -30170,19 +30260,29 @@
     field public static final int RINGING = 4; // 0x4
   }
 
+  public final class CameraCapabilities implements android.os.Parcelable {
+    ctor public CameraCapabilities(int, int);
+    method public int describeContents();
+    method public int getHeight();
+    method public int getWidth();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telecom.CameraCapabilities> CREATOR;
+  }
+
   public abstract class Conference implements android.telecom.IConferenceable {
     ctor public Conference(android.telecom.PhoneAccountHandle);
     method public final boolean addConnection(android.telecom.Connection);
     method public final void destroy();
     method public final android.telecom.AudioState getAudioState();
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
-    method public long getConnectTimeMillis();
+    method public final long getConnectTimeMillis();
     method public final int getConnectionCapabilities();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle();
     method public android.telecom.Connection getPrimaryConnection();
     method public final int getState();
+    method public final android.telecom.StatusHints getStatusHints();
     method public void onAudioStateChanged(android.telecom.AudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
@@ -30201,8 +30301,8 @@
     method public final void setConnectionCapabilities(int);
     method public final void setDisconnected(android.telecom.DisconnectCause);
     method public final void setOnHold();
-    field public static long CONNECT_TIME_NOT_SPECIFIED;
-    field protected android.telecom.PhoneAccountHandle mPhoneAccount;
+    method public final void setStatusHints(android.telecom.StatusHints);
+    field public static final long CONNECT_TIME_NOT_SPECIFIED = 0L; // 0x0L
   }
 
   public abstract class Connection implements android.telecom.IConferenceable {
@@ -30215,7 +30315,6 @@
     method public final int getAddressPresentation();
     method public final boolean getAudioModeIsVoip();
     method public final android.telecom.AudioState getAudioState();
-    method public final deprecated int getCallCapabilities();
     method public final java.lang.String getCallerDisplayName();
     method public final int getCallerDisplayNamePresentation();
     method public final android.telecom.Conference getConference();
@@ -30224,8 +30323,8 @@
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final int getState();
     method public final android.telecom.StatusHints getStatusHints();
+    method public final android.telecom.Connection.VideoProvider getVideoProvider();
     method public final boolean isRingbackRequested();
-    method protected void notifyConferenceStarted();
     method public void onAbort();
     method public void onAnswer();
     method public void onAudioStateChanged(android.telecom.AudioState);
@@ -30241,7 +30340,6 @@
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
-    method public final deprecated void setCallCapabilities(int);
     method public final void setCallerDisplayName(java.lang.String, int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.IConferenceable>);
@@ -30275,6 +30373,38 @@
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
+  public static abstract class Connection.VideoProvider {
+    ctor public Connection.VideoProvider();
+    method public void changeCallDataUsage(long);
+    method public void changeCameraCapabilities(android.telecom.CameraCapabilities);
+    method public void changePeerDimensions(int, int);
+    method public void changeVideoQuality(int);
+    method public void handleCallSessionEvent(int);
+    method public abstract void onRequestCameraCapabilities();
+    method public abstract void onRequestConnectionDataUsage();
+    method public abstract void onSendSessionModifyRequest(android.telecom.VideoProfile);
+    method public abstract void onSendSessionModifyResponse(android.telecom.VideoProfile);
+    method public abstract void onSetCamera(java.lang.String);
+    method public abstract void onSetDeviceOrientation(int);
+    method public abstract void onSetDisplaySurface(android.view.Surface);
+    method public abstract void onSetPauseImage(java.lang.String);
+    method public abstract void onSetPreviewSurface(android.view.Surface);
+    method public abstract void onSetZoom(float);
+    method public void receiveSessionModifyRequest(android.telecom.VideoProfile);
+    method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
+    field public static final int SESSION_EVENT_CAMERA_FAILURE = 5; // 0x5
+    field public static final int SESSION_EVENT_CAMERA_READY = 6; // 0x6
+    field public static final int SESSION_EVENT_RX_PAUSE = 1; // 0x1
+    field public static final int SESSION_EVENT_RX_RESUME = 2; // 0x2
+    field public static final int SESSION_EVENT_TX_START = 3; // 0x3
+    field public static final int SESSION_EVENT_TX_STOP = 4; // 0x4
+    field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
+    field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
+    field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
+    field public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; // 0x1
+    field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
+  }
+
   public final class ConnectionRequest implements android.os.Parcelable {
     ctor public ConnectionRequest(android.telecom.PhoneAccountHandle, android.net.Uri, android.os.Bundle);
     method public int describeContents();
@@ -30344,14 +30474,51 @@
 
   public abstract class InCallService extends android.app.Service {
     ctor public InCallService();
-    method public android.telecom.Phone getPhone();
+    method public final boolean canAddCall();
+    method public final android.telecom.AudioState getAudioState();
+    method public final java.util.List<android.telecom.Call> getCalls();
+    method public deprecated android.telecom.Phone getPhone();
+    method public void onAudioStateChanged(android.telecom.AudioState);
     method public android.os.IBinder onBind(android.content.Intent);
-    method public void onPhoneCreated(android.telecom.Phone);
-    method public void onPhoneDestroyed(android.telecom.Phone);
+    method public void onBringToForeground(boolean);
+    method public void onCallAdded(android.telecom.Call);
+    method public void onCallRemoved(android.telecom.Call);
+    method public void onCanAddCallChanged(boolean);
+    method public deprecated void onPhoneCreated(android.telecom.Phone);
+    method public deprecated void onPhoneDestroyed(android.telecom.Phone);
+    method public final void setAudioRoute(int);
+    method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
   }
 
-  public final class Phone {
+  public static abstract class InCallService.VideoCall {
+    ctor public InCallService.VideoCall();
+    method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback);
+    method public abstract void requestCallDataUsage();
+    method public abstract void requestCameraCapabilities();
+    method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile);
+    method public abstract void sendSessionModifyResponse(android.telecom.VideoProfile);
+    method public abstract void setCamera(java.lang.String);
+    method public abstract void setDeviceOrientation(int);
+    method public abstract void setDisplaySurface(android.view.Surface);
+    method public abstract void setPauseImage(java.lang.String);
+    method public abstract void setPreviewSurface(android.view.Surface);
+    method public abstract void setZoom(float);
+    method public abstract void unregisterCallback();
+  }
+
+  public static abstract class InCallService.VideoCall.Callback {
+    ctor public InCallService.VideoCall.Callback();
+    method public abstract void onCallDataUsageChanged(long);
+    method public abstract void onCallSessionEvent(int);
+    method public abstract void onCameraCapabilitiesChanged(android.telecom.CameraCapabilities);
+    method public abstract void onPeerDimensionsChanged(int, int);
+    method public abstract void onSessionModifyRequestReceived(android.telecom.VideoProfile);
+    method public abstract void onSessionModifyResponseReceived(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
+    method public abstract void onVideoQualityChanged(int);
+  }
+
+  public final deprecated class Phone {
     method public final void addListener(android.telecom.Phone.Listener);
     method public final boolean canAddCall();
     method public final android.telecom.AudioState getAudioState();
@@ -30359,8 +30526,6 @@
     method public final void removeListener(android.telecom.Phone.Listener);
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
-    method public final void setProximitySensorOff(boolean);
-    method public final void setProximitySensorOn();
   }
 
   public static abstract class Phone.Listener {
@@ -30412,7 +30577,6 @@
     ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
     method public android.telecom.PhoneAccount.Builder addSupportedUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount build();
-    method public android.telecom.PhoneAccount.Builder setAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
     method public android.telecom.PhoneAccount.Builder setCapabilities(int);
     method public android.telecom.PhoneAccount.Builder setHighlightColor(int);
@@ -30528,12 +30692,14 @@
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void addNewUnknownCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
     method public void cancelMissedCallsNotification();
-    method public void clearAccounts();
+    method public deprecated void clearAccounts();
+    method public void clearPhoneAccounts();
     method public boolean endCall();
     method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
     method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
     method public int getAllPhoneAccountsCount();
+    method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
     method public int getCallState();
     method public android.telecom.PhoneAccountHandle getConnectionManager();
     method public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String);
@@ -30543,10 +30709,10 @@
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
     method public java.util.List<android.telecom.PhoneAccountHandle> getRegisteredConnectionManagers();
+    method public android.telecom.PhoneAccountHandle getSimCallManager();
+    method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
-    method public boolean handleMmi(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public boolean hasMultipleCallCapableAccounts();
-    method public boolean hasVoiceMailNumber(android.telecom.PhoneAccountHandle);
+    method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isRinging();
     method public boolean isTtySupported();
@@ -30557,6 +30723,7 @@
     method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
+    field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
@@ -30606,39 +30773,29 @@
     field public static final int TX_ENABLED = 1; // 0x1
   }
 
-  public class Voicemail implements android.os.Parcelable {
-    method public static android.telecom.Voicemail.Builder createForInsertion(long, java.lang.String);
-    method public int describeContents();
-    method public long getDuration();
-    method public long getId();
-    method public java.lang.String getNumber();
-    method public java.lang.String getSourceData();
-    method public java.lang.String getSourcePackage();
-    method public long getTimestampMillis();
-    method public android.net.Uri getUri();
-    method public boolean hasContent();
-    method public boolean isRead();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telecom.Voicemail> CREATOR;
-  }
-
-  public static class Voicemail.Builder {
-    method public android.telecom.Voicemail build();
-    method public android.telecom.Voicemail.Builder setDuration(long);
-    method public android.telecom.Voicemail.Builder setHasContent(boolean);
-    method public android.telecom.Voicemail.Builder setId(long);
-    method public android.telecom.Voicemail.Builder setIsRead(boolean);
-    method public android.telecom.Voicemail.Builder setNumber(java.lang.String);
-    method public android.telecom.Voicemail.Builder setSourceData(java.lang.String);
-    method public android.telecom.Voicemail.Builder setSourcePackage(java.lang.String);
-    method public android.telecom.Voicemail.Builder setTimestamp(long);
-    method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
-  }
-
 }
 
 package android.telephony {
 
+  public class CarrierConfigManager {
+    ctor public CarrierConfigManager();
+    method public android.os.Bundle getConfig();
+    method public android.os.Bundle getConfigForSubId(int);
+    method public static android.os.Bundle getDefaultConfig();
+    method public void reloadCarrierConfigForSubId(int);
+    method public void updateConfigForPhoneId(int, java.lang.String);
+    field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.intent.action.carrier_config_changed";
+    field public static final java.lang.String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
+    field public static final java.lang.String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
+    field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
+    field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
+    field public static final java.lang.String SHORT_VVM_PORT_NUMBER = "string_vvm_port_number";
+    field public static final java.lang.String STRING_VVM_DESTINATION_NUMBER = "string_vvm_destination_number";
+    field public static final java.lang.String STRING_VVM_TYPE = "string_vvm_type";
+    field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
+  }
+
   public final class CellIdentityCdma implements android.os.Parcelable {
     method public int describeContents();
     method public int getBasestationId();
@@ -31010,7 +31167,8 @@
   public class SmsMessage {
     method public static int[] calculateLength(java.lang.CharSequence, boolean);
     method public static int[] calculateLength(java.lang.String, boolean);
-    method public static android.telephony.SmsMessage createFromPdu(byte[]);
+    method public static deprecated android.telephony.SmsMessage createFromPdu(byte[]);
+    method public static android.telephony.SmsMessage createFromPdu(byte[], java.lang.String);
     method public java.lang.String getDisplayMessageBody();
     method public java.lang.String getDisplayOriginatingAddress();
     method public java.lang.String getEmailBody();
@@ -31126,6 +31284,7 @@
     method public boolean getDataEnabled(int);
     method public int getDataState();
     method public java.lang.String getDeviceId();
+    method public java.lang.String getDeviceId(int);
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getLine1Number();
@@ -31136,6 +31295,7 @@
     method public java.lang.String getNetworkOperator();
     method public java.lang.String getNetworkOperatorName();
     method public int getNetworkType();
+    method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f2be45c..c3a1555 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -849,10 +849,10 @@
         }
 
         public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
-            final Network network = ConnectivityManager.getProcessDefaultNetwork();
+            final ConnectivityManager cm = ConnectivityManager.from(getSystemContext());
+            final Network network = cm.getBoundNetworkForProcess();
             if (network != null) {
-                Proxy.setHttpProxySystemProperty(
-                        ConnectivityManager.from(getSystemContext()).getDefaultProxy());
+                Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
             } else {
                 Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
             }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2ef046d..641f5d2 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -125,6 +125,7 @@
 import android.service.fingerprint.IFingerprintService;
 import android.service.fingerprint.FingerprintManager;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.content.ClipboardManager;
@@ -768,6 +769,12 @@
                 IBinder b = ServiceManager.getService(APPWIDGET_SERVICE);
                 return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
             }});
+
+        registerService(CARRIER_CONFIG_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                return new CarrierConfigManager();
+            }
+        });
     }
 
     static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b8f4bf8..3efbc2d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2009-2014 The Android Open Source Project
+ * Copyright (C) 2009-2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,6 +19,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.ScanCallback;
@@ -32,6 +34,9 @@
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.app.ActivityThread;
+import android.os.SystemProperties;
+import android.os.Binder;
 import android.util.Log;
 import android.util.Pair;
 
@@ -154,6 +159,24 @@
     public static final int STATE_TURNING_OFF = 13;
 
     /**
+     * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on.
+     * @hide
+     */
+    public static final int STATE_BLE_TURNING_ON = 14;
+
+    /**
+     * Indicates the local Bluetooth adapter is in LE only mode.
+     * @hide
+     */
+    public static final int STATE_BLE_ON = 15;
+
+    /**
+     * Indicates the local Bluetooth adapter is turning off LE only mode.
+     * @hide
+     */
+    public static final int STATE_BLE_TURNING_OFF = 16;
+
+    /**
      * Activity Action: Show a system activity that requests discoverable mode.
      * This activity will also request the user to turn on Bluetooth if it
      * is not currently enabled.
@@ -209,6 +232,23 @@
             "android.bluetooth.adapter.action.REQUEST_ENABLE";
 
     /**
+     * Activity Action: Show a system activity that allows user to enable BLE scans even when
+     * Bluetooth is turned off.<p>
+     *
+     * Notification of result of this activity is posted using
+     * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
+     * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
+     * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
+     * error occurred.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
+            "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+
+    /**
      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
      * has changed.
      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
@@ -347,6 +387,39 @@
     public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
           "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
 
+    /**
+     * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
+     * @hide
+     */
+    public static final String ACTION_BLE_STATE_CHANGED =
+        "anrdoid.bluetooth.adapter.action.BLE_STATE_CHANGED";
+
+    /**
+     * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
+     * by BLE Always on enabled application to know the ACL_CONNECTED event
+     * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
+     * as Bluetooth LE is the only feature available in STATE_BLE_ON
+     *
+     * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which
+     * works in Bluetooth state STATE_ON
+     * @hide
+     */
+    public static final String ACTION_BLE_ACL_CONNECTED =
+        "android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
+
+    /**
+     * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
+     * by BLE Always on enabled application to know the ACL_DISCONNECTED event
+     * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth
+     * LE is the only feature available in STATE_BLE_ON
+     *
+     * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which
+     * works in Bluetooth state STATE_ON
+     * @hide
+     */
+    public static final String ACTION_BLE_ACL_DISCONNECTED =
+        "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
+
     /** The profile is in disconnected state */
     public static final int STATE_DISCONNECTED  = 0;
     /** The profile is in connecting state */
@@ -358,6 +431,19 @@
 
     /** @hide */
     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
+    private final IBinder mToken;
+
+
+    /** When creating a ServerSocket using listenUsingRfcommOn() or
+     *  listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create
+     *  a ServerSocket that auto assigns a channel number to the first
+     *  bluetooth socket.
+     *  The channel number assigned to this first Bluetooth Socket will
+     *  be stored in the ServerSocket, and reused for subsequent Bluetooth
+     *  sockets.
+     * @hide */
+    public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;
+
 
     private static final int ADDRESS_LENGTH = 17;
 
@@ -416,6 +502,7 @@
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         mManagerService = managerService;
         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
+        mToken = new Binder();
     }
 
     /**
@@ -462,11 +549,9 @@
      * on this device before calling this method.
      */
     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
-        if (getState() != STATE_ON) {
-            return null;
-        }
+        if (!getLeAccess()) return null;
         if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) {
-            Log.e(TAG, "bluetooth le advertising not supported");
+            Log.e(TAG, "Bluetooth LE advertising not supported");
             return null;
         }
         synchronized(mLock) {
@@ -481,9 +566,7 @@
      * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
      */
     public BluetoothLeScanner getBluetoothLeScanner() {
-        if (getState() != STATE_ON) {
-            return null;
-        }
+        if (!getLeAccess()) return null;
         synchronized(mLock) {
             if (sBluetoothLeScanner == null) {
                 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
@@ -501,7 +584,6 @@
      * @return true if the local adapter is turned on
      */
     public boolean isEnabled() {
-
         try {
             synchronized(mManagerCallback) {
                 if (mService != null) return mService.isEnabled();
@@ -511,6 +593,178 @@
     }
 
     /**
+     * Return true if Bluetooth LE(Always BLE On feature) is currently
+     * enabled and ready for use
+     * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON
+     *
+     * @return true if the local Bluetooth LE adapter is turned on
+     * @hide
+     */
+     public boolean isLeEnabled() {
+        final int state = getLeState();
+        if (state == BluetoothAdapter.STATE_ON) {
+            if (DBG) Log.d (TAG, "STATE_ON");
+        } else if (state == BluetoothAdapter.STATE_BLE_ON) {
+            if (DBG) Log.d (TAG, "STATE_BLE_ON");
+        } else {
+            if (DBG) Log.d (TAG, "STATE_OFF");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Performs action based on user action to turn BT ON
+     * or OFF if BT is in BLE_ON state
+     */
+    private void notifyUserAction(boolean enable) {
+        if (mService == null) {
+            Log.e(TAG, "mService is null");
+            return;
+        }
+
+        try {
+            if (enable) {
+                mService.onLeServiceUp(); //NA:TODO implementation pending
+            } else {
+                mService.onBrEdrDown(); //NA:TODO implementation pending
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+    }
+
+    /**
+     * Returns true if LE only mode is enabled, that is apps
+     * have authorization to turn only BT ON and the calling
+     * app has privilage to do so
+     */
+    private boolean isLEAlwaysOnEnabled() {
+        boolean ret = false;
+        if (SystemProperties.getBoolean("ro.bluetooth.blealwayson", true) == true) {
+            Log.v(TAG, "LE always on mode is enabled");
+            // TODO: System API authorization check
+            ret = true;
+        } else {
+            Log.v(TAG, "LE always on mode is disabled");
+            ret = false;
+        }
+        return ret;
+    }
+
+    /**
+     * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
+     *
+     * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
+     * to STATE_OFF and completely shut-down Bluetooth
+     *
+     * <p> If the Adapter state is STATE_ON, This would unregister the existance of
+     * special Bluetooth LE application and hence the further turning off of Bluetooth
+     * from UI would ensure the complete turn-off of Bluetooth rather than staying back
+     * BLE only state
+     *
+     * <p>This is an asynchronous call: it will return immediately, and
+     * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
+     * to be notified of subsequent adapter state changes If this call returns
+     * true, then the adapter state will immediately transition from {@link
+     * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
+     * later transition to either {@link #STATE_BLE_ON} or {@link
+     * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications
+     * If this call returns false then there was an
+     * immediate problem that will prevent the QAdapter from being turned off -
+     * such as the QAadapter already being turned off.
+     *
+     * @return true to indicate success, or false on
+     *         immediate error
+     * @hide
+     */
+    public boolean disableBLE() {
+        if (isLEAlwaysOnEnabled() != true) return false;
+
+        int state = getLeState();
+        if (state == BluetoothAdapter.STATE_ON) {
+            if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable");
+            try {
+                mManagerService.updateBleAppCount(mToken, false);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+            return true;
+
+        } else if (state == BluetoothAdapter.STATE_BLE_ON) {
+            if (DBG) Log.d (TAG, "STATE_BLE_ON");
+            int bleAppCnt = 0;
+            try {
+                bleAppCnt = mManagerService.updateBleAppCount(mToken, false);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+            if (bleAppCnt == 0) {
+                // Disable only if there are no other clients
+                notifyUserAction(false);
+            }
+            return true;
+        }
+
+        if (DBG) Log.d (TAG, "STATE_OFF: Already disabled");
+        return false;
+    }
+
+    /**
+     * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would
+     * EnableBLE, EnableBLE brings-up Bluetooth so that application can access
+     * only LE related feature (Bluetooth GATT layers interfaces using the respective class)
+     * EnableBLE in turn registers the existance of a special App which wants to
+     * turn on Bluetooth Low enrgy part without making it visible at the settings UI
+     * as Bluetooth ON.
+     * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers
+     * the existance of special Application and doesn't do anything to current BT state.
+     * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth
+     * would stay in BLE_ON state so that LE features are still acessible to the special
+     * Applications.
+     *
+     * <p>This is an asynchronous call: it will return immediately, and
+     * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
+     * to be notified of subsequent adapter state changes. If this call returns
+     * true, then the adapter state will immediately transition from {@link
+     * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time
+     * later transition to either {@link #STATE_OFF} or {@link
+     * #STATE_BLE_ON}. If this call returns false then there was an
+     * immediate problem that will prevent the adapter from being turned on -
+     * such as Airplane mode, or the adapter is already turned on.
+     * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various
+     * states, It includes all the classic Bluetooth Adapter states along with
+     * internal BLE only states
+     *
+     * @return true to indicate Bluetooth LE start-up has begun, or false on
+     *         immediate error
+     * @hide
+     */
+    public boolean enableBLE() {
+        if (isLEAlwaysOnEnabled() != true) return false;
+
+        if (isLeEnabled() == true) {
+            if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
+            try {
+                mManagerService.updateBleAppCount(mToken, true);
+            } catch (RemoteException e) {
+                Log.e(TAG, "", e);
+            }
+            return true;
+        }
+
+        try {
+            if (DBG) Log.d(TAG, "Calling enableBLE");
+            mManagerService.updateBleAppCount(mToken, true);
+            return mManagerService.enable();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+
+        return false;
+    }
+
+    /**
      * Get the current state of the local Bluetooth adapter.
      * <p>Possible return values are
      * {@link #STATE_OFF},
@@ -528,6 +782,13 @@
                 {
                     int state=  mService.getState();
                     if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+                    //consider all internal states as OFF
+                    if (state == BluetoothAdapter.STATE_BLE_ON
+                        || state == BluetoothAdapter.STATE_BLE_TURNING_ON
+                        || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
+                        if (VDBG) Log.d(TAG, "Consider internal state as OFF");
+                        state = BluetoothAdapter.STATE_OFF;
+                    }
                     return state;
                 }
                 // TODO(BT) there might be a small gap during STATE_TURNING_ON that
@@ -539,6 +800,49 @@
     }
 
     /**
+     * Get the current state of the local Bluetooth adapter
+     * <p>This returns current internal state of Adapter including LE ON/OFF
+     *
+     * <p>Possible return values are
+     * {@link #STATE_OFF},
+     * {@link #STATE_BLE_TURNING_ON},
+     * {@link #STATE_BLE_ON},
+     * {@link #STATE_TURNING_ON},
+     * {@link #STATE_ON},
+     * {@link #STATE_TURNING_OFF},
+     * {@link #STATE_BLE_TURNING_OFF}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
+     * @return current state of Bluetooth adapter
+     * @hide
+     */
+    public int getLeState() {
+        try {
+            synchronized(mManagerCallback) {
+                if (mService != null)
+                {
+                    int state=  mService.getState();
+                    if (VDBG) Log.d(TAG,"getLeState() returning " + state);
+                    return state;
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return BluetoothAdapter.STATE_OFF;
+    }
+
+    boolean getLeAccess() {
+        if(getLeState() == STATE_ON)
+            return true;
+
+        else if (getLeState() == STATE_BLE_ON)
+            return true; // TODO: FILTER SYSTEM APPS HERE <--
+
+        return false;
+    }
+
+    /**
      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
      * user action to turn on Bluetooth.
      * <p>This powers on the underlying Bluetooth hardware, and starts all
@@ -566,10 +870,23 @@
      *         immediate error
      */
     public boolean enable() {
+        int state = STATE_OFF;
         if (isEnabled() == true){
             if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
             return true;
         }
+        //Use service interface to get the exact state
+        if (mService != null) {
+            try {
+               state = mService.getState();
+            } catch (RemoteException e) {Log.e(TAG, "", e);}
+        }
+
+        if (state == BluetoothAdapter.STATE_BLE_ON) {
+                Log.e(TAG, "BT is in BLE_ON State");
+                notifyUserAction(true);
+                return true;
+        }
         try {
             return mManagerService.enable();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -919,6 +1236,22 @@
     }
 
     /**
+     * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
+     *
+     * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
+     * fetch scan results even when Bluetooth is turned off.<p>
+     *
+     * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isBleScanAlwaysAvailable() {
+        // TODO: implement after Settings UI change.
+        return false;
+    }
+
+    /**
      * Returns whether peripheral mode is supported.
      *
      * @hide
@@ -964,6 +1297,27 @@
     }
 
     /**
+     * Return true if hardware has entries available for matching beacons
+     *
+     * @return true if there are hw entries available for matching beacons
+     * @hide
+     */
+    public boolean isHardwareTrackingFiltersAvailable() {
+        if (getState() != STATE_ON) return false;
+        try {
+            IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+            if (iGatt == null) {
+                // BLE is not supported
+                return false;
+            }
+            return (iGatt.numHwTrackFiltersAvailable() != 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return false;
+    }
+
+    /**
      * Return the record of {@link BluetoothActivityEnergyInfo} object that
      * has the activity and energy info. This can be used to ascertain what
      * the controller has been up to, since the last sample.
@@ -1092,6 +1446,9 @@
         BluetoothServerSocket socket = new BluetoothServerSocket(
                 BluetoothSocket.TYPE_RFCOMM, true, true, channel);
         int errno = socket.mSocket.bindListen();
+        if(channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+            socket.setChannel(socket.mSocket.getPort());
+        }
         if (errno != 0) {
             //TODO(BT): Throw the same exception error code
             // that the previous code was using.
@@ -1226,6 +1583,9 @@
         BluetoothServerSocket socket = new BluetoothServerSocket(
                 BluetoothSocket.TYPE_RFCOMM, false, false, port);
         int errno = socket.mSocket.bindListen();
+        if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+            socket.setChannel(socket.mSocket.getPort());
+        }
         if (errno != 0) {
             //TODO(BT): Throw the same exception error code
             // that the previous code was using.
@@ -1248,6 +1608,9 @@
         BluetoothServerSocket socket = new BluetoothServerSocket(
                 BluetoothSocket.TYPE_RFCOMM, false, true, port);
         int errno = socket.mSocket.bindListen();
+        if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+            socket.setChannel(socket.mSocket.getPort());
+        }
         if (errno < 0) {
             //TODO(BT): Throw the same exception error code
             // that the previous code was using.
@@ -1278,6 +1641,30 @@
     }
 
     /**
+     * Construct an encrypted, authenticated, L2CAP server socket.
+     * Call #accept to retrieve connections to this socket.
+     * @return An L2CAP BluetoothServerSocket
+     * @throws IOException On error, for example Bluetooth not available, or
+     *                     insufficient permissions.
+     * @hide
+     */
+    public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
+        BluetoothServerSocket socket = new BluetoothServerSocket(
+                BluetoothSocket.TYPE_L2CAP, true, true, port);
+        int errno = socket.mSocket.bindListen();
+        if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+            socket.setChannel(socket.mSocket.getPort());
+        }
+        if (errno != 0) {
+            //TODO(BT): Throw the same exception error code
+            // that the previous code was using.
+            //socket.mSocket.throwErrnoNative(errno);
+            throw new IOException("Error: " + errno);
+        }
+        return socket;
+    }
+
+    /**
      * Read the local Out of Band Pairing Data
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
@@ -1356,6 +1743,9 @@
         } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
             BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
             return true;
+        } else if (profile == BluetoothProfile.SAP) {
+            BluetoothSap sap = new BluetoothSap(context, listener);
+            return true;
         } else {
             return false;
         }
@@ -1420,6 +1810,10 @@
                 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
                 headsetClient.close();
                 break;
+            case BluetoothProfile.SAP:
+                BluetoothSap sap = (BluetoothSap)proxy;
+                sap.close();
+                break;
         }
     }
 
@@ -1463,6 +1857,10 @@
                     }
                 }
             }
+
+            public void onBrEdrDown() {
+                if (VDBG) Log.i(TAG, "on QBrEdrDown: ");
+            }
     };
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index bb0d0a3..bfc374fb 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -302,6 +302,12 @@
      */
     public static final int DEVICE_TYPE_DUAL = 3;
 
+
+    /** @hide */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SDP_RECORD =
+            "android.bluetooth.device.action.SDP_RECORD";
+
     /**
      * Broadcast Action: This intent is used to broadcast the {@link UUID}
      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
@@ -376,6 +382,9 @@
     /**@hide*/
     public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
 
+    /**@hide*/
+    public static final int REQUEST_TYPE_SIM_ACCESS = 4;
+
     /**
      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
      * Contains package name to return reply intent to.
@@ -526,6 +535,13 @@
      */
     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
 
+    /** @hide */
+    public static final String EXTRA_SDP_RECORD =
+        "android.bluetooth.device.extra.SDP_RECORD";
+
+    /** @hide */
+    public static final String EXTRA_SDP_SEARCH_STATUS =
+            "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
     /**
      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
@@ -593,7 +609,9 @@
         public void onBluetoothServiceUp(IBluetooth bluetoothService)
                 throws RemoteException {
             synchronized (BluetoothDevice.class) {
-                sService = bluetoothService;
+                if (sService == null) {
+                    sService = bluetoothService;
+                }
             }
         }
 
@@ -603,6 +621,11 @@
                 sService = null;
             }
         }
+
+        public void onBrEdrDown()
+        {
+            if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
+        }
     };
     /**
      * Create a new BluetoothDevice
@@ -1017,7 +1040,7 @@
      *         or null on error
      */
      public ParcelUuid[] getUuids() {
-         if (sService == null) {
+         if (sService == null || isBluetoothEnabled() == false) {
             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
              return null;
          }
@@ -1044,7 +1067,7 @@
       */
      public boolean fetchUuidsWithSdp() {
         IBluetooth service = sService;
-        if (service == null) {
+        if (service == null || isBluetoothEnabled() == false) {
             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
             return false;
         }
@@ -1054,28 +1077,38 @@
             return false;
     }
 
+     /**
+      * Perform a service discovery on the remote device to get the SDP records associated
+      * with the specified UUID.
+      *
+      * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
+      * with the SDP records found on the remote end. If there is an error
+      * in getting the SDP records or if the process takes a long time,
+      * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
+      * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
+      * Detailed status error codes can be found by members of the Bluetooth package in
+      * the AbstractionLayer class.
+      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+      * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
+      * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
+      * for.
+      *
+      * @return False if the sanity check fails, True if the process
+      *               of initiating an ACL connection to the remote device
+      *               was started.
+      */
      /** @hide */
-     public boolean fetchMasInstances() {
+     public boolean sdpSearch(ParcelUuid uuid) {
          if (sService == null) {
-             Log.e(TAG, "BT not enabled. Cannot query remote device for MAS instances");
+             Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
              return false;
          }
          try {
-             return sService.fetchRemoteMasInstances(this);
+             return sService.sdpSearch(this,uuid);
          } catch (RemoteException e) {Log.e(TAG, "", e);}
          return false;
      }
 
-    /** @hide */
-    public int getServiceChannel(ParcelUuid uuid) {
-        //TODO(BT)
-        /*
-         try {
-             return sService.getRemoteServiceChannel(this, uuid);
-         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
-         return BluetoothDevice.ERROR;
-    }
-
     /**
      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
@@ -1154,6 +1187,15 @@
         return false;
     }
 
+     boolean isBluetoothEnabled() {
+         boolean ret = false;
+         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+         if (adapter != null && adapter.isEnabled() == true) {
+             ret = true;
+         }
+         return ret;
+     }
+
     /**
      * Requires {@link android.Manifest.permission#BLUETOOTH}.
      * @return Whether the phonebook access is allowed to this device. Can be
@@ -1231,6 +1273,44 @@
     }
 
     /**
+     * Requires {@link android.Manifest.permission#BLUETOOTH}.
+     * @return Whether the Sim access is allowed to this device. Can be
+     *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+     * @hide
+     */
+    public int getSimAccessPermission() {
+        if (sService == null) {
+            return ACCESS_UNKNOWN;
+        }
+        try {
+            return sService.getSimAccessPermission(this);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    /**
+     * Sets whether the Sim access is allowed to this device.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
+     *              {@link #ACCESS_REJECTED}.
+     * @return Whether the value has been successfully set.
+     * @hide
+     */
+    public boolean setSimAccessPermission(int value) {
+        if (sService == null) {
+            return false;
+        }
+        try {
+            return sService.setSimAccessPermission(this, value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return false;
+    }    
+    
+    /**
      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
      * outgoing connection to this remote device on given channel.
      * <p>The remote device will be authenticated and communication on this
@@ -1256,11 +1336,45 @@
      * @hide
      */
     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
+        if (isBluetoothEnabled() == false) {
+            Log.e(TAG, "Bluetooth is not enabled");
+            throw new IOException();
+        }
         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
                 null);
     }
 
     /**
+     * Create an L2cap {@link BluetoothSocket} ready to start a secure
+     * outgoing connection to this remote device on given channel.
+     * <p>The remote device will be authenticated and communication on this
+     * socket will be encrypted.
+     * <p> Use this socket only if an authenticated socket link is possible.
+     * Authentication refers to the authentication of the link key to
+     * prevent man-in-the-middle type of attacks.
+     * For example, for Bluetooth 2.1 devices, if any of the devices does not
+     * have an input and output capability or just has the ability to
+     * display a numeric key, a secure socket connection is not possible.
+     * In such a case, use {#link createInsecureRfcommSocket}.
+     * For more details, refer to the Security Model section 5.2 (vol 3) of
+     * Bluetooth Core Specification version 2.1 + EDR.
+     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
+     * connection.
+     * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
+     * @param channel L2cap PSM/channel to connect to
+     * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+     * @throws IOException on error, for example Bluetooth not available, or
+     *                     insufficient permissions
+     * @hide
+     */
+    public BluetoothSocket createL2capSocket(int channel) throws IOException {
+        return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
+                null);
+    }
+
+    /**
      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
      * outgoing connection to this remote device using SDP lookup of uuid.
      * <p>This is designed to be used with {@link
@@ -1292,6 +1406,11 @@
      *                     insufficient permissions
      */
     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
+        if (isBluetoothEnabled() == false) {
+            Log.e(TAG, "Bluetooth is not enabled");
+            throw new IOException();
+        }
+
         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
                 new ParcelUuid(uuid));
     }
@@ -1325,6 +1444,10 @@
      *                     insufficient permissions
      */
     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
+        if (isBluetoothEnabled() == false) {
+            Log.e(TAG, "Bluetooth is not enabled");
+            throw new IOException();
+        }
         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
                 new ParcelUuid(uuid));
     }
@@ -1344,6 +1467,11 @@
      * @hide
      */
     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
+
+        if (isBluetoothEnabled() == false) {
+            Log.e(TAG, "Bluetooth is not enabled");
+            throw new IOException();
+        }
         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
                 null);
     }
@@ -1359,6 +1487,11 @@
      * @hide
      */
     public BluetoothSocket createScoSocket() throws IOException {
+
+        if (isBluetoothEnabled() == false) {
+            Log.e(TAG, "Bluetooth is not enabled");
+            throw new IOException();
+        }
         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
     }
 
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
index cdb24f4..01778b3 100644
--- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -123,4 +123,7 @@
     public void onFoundOrLost(boolean onFound, ScanResult scanResult) throws RemoteException {
     }
 
+    @Override
+    public void onScanManagerErrorCallback(int errorCode) throws RemoteException {
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 1367405..eecb073 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -103,17 +103,23 @@
      */
     public static final int MAP = 9;
 
+    /*
+     * SAP Profile
+     * @hide
+     */
+    public static final int SAP = 10;
+
     /**
      * A2DP Sink Profile
      * @hide
      */
-    public static final int A2DP_SINK = 10;
+    public static final int A2DP_SINK = 11;
 
     /**
      * AVRCP Controller Profile
      * @hide
      */
-    public static final int AVRCP_CONTROLLER = 11;
+    public static final int AVRCP_CONTROLLER = 12;
 
     /**
      * Headset Client - HFP HF Role
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
new file mode 100644
index 0000000..7b4c6f9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2008 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.bluetooth;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+
+public final class BluetoothSap implements BluetoothProfile {
+
+    private static final String TAG = "BluetoothSap";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    public static final String ACTION_CONNECTION_STATE_CHANGED =
+        "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
+
+    private IBluetoothSap mService;
+    private final Context mContext;
+    private ServiceListener mServiceListener;
+    private BluetoothAdapter mAdapter;
+
+    /** There was an error trying to obtain the state */
+    public static final int STATE_ERROR        = -1;
+
+    public static final int RESULT_FAILURE = 0;
+    public static final int RESULT_SUCCESS = 1;
+    /** Connection canceled before completion. */
+    public static final int RESULT_CANCELED = 2;
+
+    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+            new IBluetoothStateChangeCallback.Stub() {
+                public void onBluetoothStateChange(boolean up) {
+                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                    if (!up) {
+                        if (VDBG) Log.d(TAG,"Unbinding service...");
+                        synchronized (mConnection) {
+                            try {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    } else {
+                        synchronized (mConnection) {
+                            try {
+                                if (mService == null) {
+                                    if (VDBG) Log.d(TAG,"Binding service...");
+                                    doBind();
+                                }
+                            } catch (Exception re) {
+                                Log.e(TAG,"",re);
+                            }
+                        }
+                    }
+                }
+        };
+
+    /**
+     * Create a BluetoothSap proxy object.
+     */
+    /*package*/ BluetoothSap(Context context, ServiceListener l) {
+        if (DBG) Log.d(TAG, "Create BluetoothSap proxy object");
+        mContext = context;
+        mServiceListener = l;
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+        doBind();
+    }
+
+    boolean doBind() {
+        Intent intent = new Intent(IBluetoothMap.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        intent.setComponent(comp);
+        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+                android.os.Process.myUserHandle())) {
+            Log.e(TAG, "Could not bind to Bluetooth SAP Service with " + intent);
+            return false;
+        }
+        return true;
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Close the connection to the backing service.
+     * Other public functions of BluetoothSap will return default error
+     * results once close() has been called. Multiple invocations of close()
+     * are ok.
+     */
+    public synchronized void close() {
+        IBluetoothManager mgr = mAdapter.getBluetoothManager();
+        if (mgr != null) {
+            try {
+                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+            } catch (Exception e) {
+                Log.e(TAG,"",e);
+            }
+        }
+
+        synchronized (mConnection) {
+            if (mService != null) {
+                try {
+                    mService = null;
+                    mContext.unbindService(mConnection);
+                } catch (Exception re) {
+                    Log.e(TAG,"",re);
+                }
+            }
+        }
+        mServiceListener = null;
+    }
+
+    /**
+     * Get the current state of the BluetoothSap service.
+     * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
+     *         object is currently not connected to the Sap service.
+     */
+    public int getState() {
+        if (VDBG) log("getState()");
+        if (mService != null) {
+            try {
+                return mService.getState();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) log(Log.getStackTraceString(new Throwable()));
+        }
+        return BluetoothSap.STATE_ERROR;
+    }
+
+    /**
+     * Get the currently connected remote Bluetooth device (PCE).
+     * @return The remote Bluetooth device, or null if not in connected or
+     *         connecting state, or if this proxy object is not connected to
+     *         the Sap service.
+     */
+    public BluetoothDevice getClient() {
+        if (VDBG) log("getClient()");
+        if (mService != null) {
+            try {
+                return mService.getClient();
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) log(Log.getStackTraceString(new Throwable()));
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if the specified Bluetooth device is connected.
+     * Returns false if not connected, or if this proxy object is not
+     * currently connected to the Sap service.
+     */
+    public boolean isConnected(BluetoothDevice device) {
+        if (VDBG) log("isConnected(" + device + ")");
+        if (mService != null) {
+            try {
+                return mService.isConnected(device);
+            } catch (RemoteException e) {Log.e(TAG, e.toString());}
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) log(Log.getStackTraceString(new Throwable()));
+        }
+        return false;
+    }
+
+    /**
+     * Initiate connection. Initiation of outgoing connections is not
+     * supported for SAP server.
+     */
+    public boolean connect(BluetoothDevice device) {
+        if (DBG) log("connect(" + device + ")" + "not supported for SAPS");
+        return false;
+    }
+
+    /**
+     * Initiate disconnect.
+     *
+     * @param device Remote Bluetooth Device
+     * @return false on error,
+     *               true otherwise
+     */
+    public boolean disconnect(BluetoothDevice device) {
+        if (DBG) log("disconnect(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.disconnect(device);
+            } catch (RemoteException e) {
+              Log.e(TAG, Log.getStackTraceString(new Throwable()));
+              return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Get the list of connected devices. Currently at most one.
+     *
+     * @return list of connected devices
+     */
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (DBG) log("getConnectedDevices()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getConnectedDevices();
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get the list of devices matching specified states. Currently at most one.
+     *
+     * @return list of matching devices
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+        if (DBG) log("getDevicesMatchingStates()");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getDevicesMatchingConnectionStates(states);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return new ArrayList<BluetoothDevice>();
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return new ArrayList<BluetoothDevice>();
+    }
+
+    /**
+     * Get connection state of device
+     *
+     * @return device connection state
+     */
+    public int getConnectionState(BluetoothDevice device) {
+        if (DBG) log("getConnectionState(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.getConnectionState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.STATE_DISCONNECTED;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Set priority of the profile
+     *
+     * <p> The device should already be paired.
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     */
+    public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            if (priority != BluetoothProfile.PRIORITY_OFF &&
+                priority != BluetoothProfile.PRIORITY_ON) {
+              return false;
+            }
+            try {
+                return mService.setPriority(device, priority);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
+     * Get the priority of the profile.
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     */
+    public int getPriority(BluetoothDevice device) {
+        if (VDBG) log("getPriority(" + device + ")");
+        if (mService != null && isEnabled() &&
+            isValidDevice(device)) {
+            try {
+                return mService.getPriority(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+                return PRIORITY_OFF;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return PRIORITY_OFF;
+    }
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            if (DBG) log("Proxy object connected");
+            mService = IBluetoothSap.Stub.asInterface(service);
+            if (mServiceListener != null) {
+                mServiceListener.onServiceConnected(BluetoothProfile.SAP, BluetoothSap.this);
+            }
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            if (DBG) log("Proxy object disconnected");
+            mService = null;
+            if (mServiceListener != null) {
+                mServiceListener.onServiceDisconnected(BluetoothProfile.SAP);
+            }
+        }
+    };
+
+    private static void log(String msg) {
+        Log.d(TAG, msg);
+    }
+
+    private boolean isEnabled() {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON)
+            return true;
+        log("Bluetooth is Not enabled");
+        return false;
+    }
+
+    private boolean isValidDevice(BluetoothDevice device) {
+       if (device == null)
+           return false;
+
+       if (BluetoothAdapter.checkBluetoothAddress(device.getAddress()))
+           return true;
+       return false;
+    }
+
+}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index bc56e55..21024a6 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -18,6 +18,7 @@
 
 import android.os.Handler;
 import android.os.ParcelUuid;
+import android.util.Log;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -66,10 +67,11 @@
  */
 public final class BluetoothServerSocket implements Closeable {
 
+    private static final String TAG = "BluetoothServerSocket";
     /*package*/ final BluetoothSocket mSocket;
     private Handler mHandler;
     private int mMessage;
-    private final int mChannel;
+    private int mChannel;
 
     /**
      * Construct a socket for incoming connections.
@@ -84,6 +86,9 @@
             throws IOException {
         mChannel = port;
         mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null);
+        if(port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
+            mSocket.setExcludeSdp(true);
+        }
     }
 
     /**
@@ -98,6 +103,7 @@
     /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
             throws IOException {
         mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid);
+        // TODO: This is the same as mChannel = -1 - is this intentional?
         mChannel = mSocket.getPort();
     }
 
@@ -153,6 +159,7 @@
     /*package*/ void setServiceName(String ServiceName) {
         mSocket.setServiceName(ServiceName);
     }
+
     /**
      * Returns the channel on which this socket is bound.
      * @hide
@@ -160,4 +167,47 @@
     public int getChannel() {
         return mChannel;
     }
+
+    /**
+     * Sets the channel on which future sockets are bound.
+     * Currently used only when a channel is auto generated.
+     */
+    /*package*/ void setChannel(int newChannel) {
+        /* TODO: From a design/architecture perspective this is wrong.
+         *       The bind operation should be conducted through this class
+         *       and the resulting port should be kept in mChannel, and
+         *       not set from BluetoothAdapter. */
+        if(mSocket != null) {
+            if(mSocket.getPort() != newChannel) {
+                Log.w(TAG,"The port set is different that the underlying port. mSocket.getPort(): "
+                            + mSocket.getPort() + " requested newChannel: " + newChannel);
+            }
+        }
+        mChannel = newChannel;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("ServerSocket: Type: ");
+        switch(mSocket.getConnectionType()) {
+            case BluetoothSocket.TYPE_RFCOMM:
+            {
+                sb.append("TYPE_RFCOMM");
+                break;
+            }
+            case BluetoothSocket.TYPE_L2CAP:
+            {
+                sb.append("TYPE_L2CAP");
+                break;
+            }
+            case BluetoothSocket.TYPE_SCO:
+            {
+                sb.append("TYPE_SCO");
+                break;
+            }
+        }
+        sb.append(" Channel: ").append(mChannel);
+        return sb.toString();
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 36997e5..5702d11 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -21,6 +21,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.io.BufferedInputStream;
 import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -29,6 +30,8 @@
 import java.util.Locale;
 import java.util.UUID;
 import android.net.LocalSocket;
+
+import java.nio.Buffer;
 import java.nio.ByteOrder;
 import java.nio.ByteBuffer;
 /**
@@ -86,17 +89,19 @@
 
     /** @hide */
     public static final int MAX_RFCOMM_CHANNEL = 30;
+    /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;
 
     /** Keep TYPE_ fields in sync with BluetoothSocket.cpp */
-    /*package*/ static final int TYPE_RFCOMM = 1;
-    /*package*/ static final int TYPE_SCO = 2;
-    /*package*/ static final int TYPE_L2CAP = 3;
+    public static final int TYPE_RFCOMM = 1;
+    public static final int TYPE_SCO = 2;
+    public static final int TYPE_L2CAP = 3;
 
     /*package*/ static final int EBADFD = 77;
     /*package*/ static final int EADDRINUSE = 98;
 
     /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
     /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
+    /*package*/ static final int BTSOCK_FLAG_NO_SDP  = 1 << 2;
 
     private final int mType;  /* one of TYPE_RFCOMM etc */
     private BluetoothDevice mDevice;    /* remote device */
@@ -106,6 +111,7 @@
     private final BluetoothInputStream mInputStream;
     private final BluetoothOutputStream mOutputStream;
     private final ParcelUuid mUuid;
+    private boolean mExcludeSdp = false;
     private ParcelFileDescriptor mPfd;
     private LocalSocket mSocket;
     private InputStream mSocketIS;
@@ -115,7 +121,11 @@
     private String mServiceName;
     private static int PROXY_CONNECTION_TIMEOUT = 5000;
 
-    private static int SOCK_SIGNAL_SIZE = 16;
+    private static int SOCK_SIGNAL_SIZE = 20;
+
+    private ByteBuffer mL2capBuffer = null;
+    private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
+    private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
 
     private enum SocketState {
         INIT,
@@ -144,12 +154,14 @@
      */
     /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
             BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
-        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1) {
+        if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
+        if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1
+                && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
             if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
                 throw new IOException("Invalid RFCOMM channel: " + port);
             }
         }
-        if(uuid != null)
+        if (uuid != null)
             mUuid = uuid;
         else mUuid = new ParcelUuid(new UUID(0, 0));
         mType = type;
@@ -172,6 +184,7 @@
         mOutputStream = new BluetoothOutputStream(this);
     }
     private BluetoothSocket(BluetoothSocket s) {
+        if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
         mUuid = s.mUuid;
         mType = s.mType;
         mAuth = s.mAuth;
@@ -179,7 +192,11 @@
         mPort = s.mPort;
         mInputStream = new BluetoothInputStream(this);
         mOutputStream = new BluetoothOutputStream(this);
+        mMaxRxPacketSize = s.mMaxRxPacketSize;
+        mMaxTxPacketSize = s.mMaxTxPacketSize;
+
         mServiceName = s.mServiceName;
+        mExcludeSdp = s.mExcludeSdp;
     }
     private BluetoothSocket acceptSocket(String RemoteAddr) throws IOException {
         BluetoothSocket as = new BluetoothSocket(this);
@@ -229,6 +246,8 @@
             flags |= SEC_FLAG_AUTH;
         if(mEncrypt)
             flags |= SEC_FLAG_ENCRYPT;
+        if(mExcludeSdp)
+            flags |= BTSOCK_FLAG_NO_SDP;
         return flags;
     }
 
@@ -298,7 +317,8 @@
 
         try {
             if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
-            IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+            IBluetooth bluetoothProxy =
+                    BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
             if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
             mPfd = bluetoothProxy.connectSocket(mDevice, mType,
                     mUuid, mPort, getSecurityFlags());
@@ -370,7 +390,7 @@
                     mSocketState = SocketState.LISTENING;
             }
             if (DBG) Log.d(TAG, "channel: " + channel);
-            if (mPort == -1) {
+            if (mPort <= -1) {
                 mPort = channel;
             } // else ASSERT(mPort == channel)
             ret = 0;
@@ -391,7 +411,8 @@
 
     /*package*/ BluetoothSocket accept(int timeout) throws IOException {
         BluetoothSocket acceptedSocket;
-        if (mSocketState != SocketState.LISTENING) throw new IOException("bt socket is not in listen state");
+        if (mSocketState != SocketState.LISTENING)
+            throw new IOException("bt socket is not in listen state");
         if(timeout > 0) {
             Log.d(TAG, "accept() set timeout (ms):" + timeout);
            mSocket.setSoTimeout(timeout);
@@ -427,27 +448,80 @@
     }
 
     /*package*/ int read(byte[] b, int offset, int length) throws IOException {
-        if (mSocketIS == null) throw new IOException("read is called on null InputStream");
+        int ret = 0;
         if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
-        int ret = mSocketIS.read(b, offset, length);
-        if(ret < 0)
+        if(mType == TYPE_L2CAP)
+        {
+            int bytesToRead = length;
+            if (VDBG) Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
+                    + "mL2capBuffer= " + mL2capBuffer);
+            if (mL2capBuffer == null) {
+                createL2capRxBuffer();
+            }
+            if (mL2capBuffer.remaining() == 0) {
+                if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
+                if (fillL2capRxBuffer() == -1) {
+                    return -1;
+                }
+            }
+            if (bytesToRead > mL2capBuffer.remaining()) {
+                bytesToRead = mL2capBuffer.remaining();
+            }
+            if(VDBG) Log.v(TAG, "get(): offset: " + offset
+                    + " bytesToRead: " + bytesToRead);
+            mL2capBuffer.get(b, offset, bytesToRead);
+            ret = bytesToRead;
+        }else {
+            if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
+            ret = mSocketIS.read(b, offset, length);
+        }
+        if (ret < 0)
             throw new IOException("bt socket closed, read return: " + ret);
         if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
         return ret;
     }
 
     /*package*/ int write(byte[] b, int offset, int length) throws IOException {
-        if (mSocketOS == null) throw new IOException("write is called on null OutputStream");
-        if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
-        mSocketOS.write(b, offset, length);
-        // There is no good way to confirm since the entire process is asynchronous anyway
-        if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
-        return length;
+
+        //TODO: Since bindings can exist between the SDU size and the
+        //      protocol, we might need to throw an exception instead of just
+        //      splitting the write into multiple smaller writes.
+        //      Rfcomm uses dynamic allocation, and should not have any bindings
+        //      to the actual message length.
+            if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
+            if (mType == TYPE_L2CAP) {
+                if(length <= mMaxTxPacketSize) {
+                    mSocketOS.write(b, offset, length);
+                } else {
+                    int tmpOffset = offset;
+                    int tmpLength = mMaxTxPacketSize;
+                    int endIndex = offset + length;
+                    boolean done = false;
+                    if(DBG) Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
+                            + "Packet will be divided into SDU packets of size "
+                            + mMaxTxPacketSize);
+                    do{
+                        mSocketOS.write(b, tmpOffset, tmpLength);
+                        tmpOffset += mMaxTxPacketSize;
+                        if((tmpOffset + mMaxTxPacketSize) > endIndex) {
+                            tmpLength = endIndex - tmpOffset;
+                            done = true;
+                        }
+                    } while(!done);
+
+                }
+            } else {
+                mSocketOS.write(b, offset, length);
+            }
+            // There is no good way to confirm since the entire process is asynchronous anyway
+            if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
+            return length;
     }
 
     @Override
     public void close() throws IOException {
-        if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
+        if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: "
+                + mSocketState);
         if(mSocketState == SocketState.CLOSED)
             return;
         else
@@ -457,8 +531,9 @@
                  if(mSocketState == SocketState.CLOSED)
                     return;
                  mSocketState = SocketState.CLOSED;
-                 if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
-                        ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
+                 if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort +
+                         ", mSocketIS: " + mSocketIS + ", mSocketOS: " + mSocketOS +
+                         "mSocket: " + mSocket);
                  if(mSocket != null) {
                     if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
                     mSocket.shutdownInput();
@@ -480,6 +555,47 @@
     /*package */ int getPort() {
         return mPort;
     }
+
+    /**
+     * Get the maximum supported Transmit packet size for the underlying transport.
+     * Use this to optimize the writes done to the output socket, to avoid sending
+     * half full packets.
+     * @return the maximum supported Transmit packet size for the underlying transport.
+     */
+    public int getMaxTransmitPacketSize(){
+        return mMaxTxPacketSize;
+    }
+
+    /**
+     * Get the maximum supported Receive packet size for the underlying transport.
+     * Use this to optimize the reads done on the input stream, as any call to read
+     * will return a maximum of this amount of bytes - or for some transports a
+     * multiple of this value.
+     * @return the maximum supported Receive packet size for the underlying transport.
+     */
+    public int getMaxReceivePacketSize(){
+        return mMaxRxPacketSize;
+    }
+
+    /**
+     * Get the type of the underlying connection
+     * @return one of TYPE_
+     */
+    public int getConnectionType() {
+        return mType;
+    }
+
+    /**
+     * Change if a SDP entry should be automatically created.
+     * Must be called before calling .bind, for the call to have any effect.
+     * @param mExcludeSdp <li>TRUE  - do not auto generate SDP record.
+     *                    <li>FALSE - default - auto generate SPP SDP record.
+     * @hide
+     */
+    public void setExcludeSdp(boolean excludeSdp) {
+        this.mExcludeSdp = excludeSdp;
+    }
+
     private String convertAddr(final byte[] addr)  {
         return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
                 addr[0] , addr[1], addr[2], addr[3] , addr[4], addr[5]);
@@ -487,8 +603,10 @@
     private String waitSocketSignal(InputStream is) throws IOException {
         byte [] sig = new byte[SOCK_SIGNAL_SIZE];
         int ret = readAll(is, sig);
-        if (VDBG) Log.d(TAG, "waitSocketSignal read 16 bytes signal ret: " + ret);
+        if (VDBG) Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE +
+                " bytes signal ret: " + ret);
         ByteBuffer bb = ByteBuffer.wrap(sig);
+        /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
         bb.order(ByteOrder.nativeOrder());
         int size = bb.getShort();
         if(size != SOCK_SIGNAL_SIZE)
@@ -497,19 +615,36 @@
         bb.get(addr);
         int channel = bb.getInt();
         int status = bb.getInt();
+        mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
+        mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
         String RemoteAddr = convertAddr(addr);
         if (VDBG) Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
-                + RemoteAddr + ", channel: " + channel + ", status: " + status);
+                + RemoteAddr + ", channel: " + channel + ", status: " + status
+                + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize);
         if(status != 0)
             throw new IOException("Connection failure, status: " + status);
         return RemoteAddr;
     }
+
+    private void createL2capRxBuffer(){
+        if(mType == TYPE_L2CAP) {
+            // Allocate the buffer to use for reads.
+            if(VDBG) Log.v(TAG, "  Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
+            mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
+            if(VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
+            mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
+            if(VDBG) Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" +
+                    mL2capBuffer.remaining());
+        }
+    }
+
     private int readAll(InputStream is, byte[] b) throws IOException {
         int left = b.length;
         while(left > 0) {
             int ret = is.read(b, b.length - left, left);
             if(ret <= 0)
-                 throw new IOException("read failed, socket might closed or timeout, read ret: " + ret);
+                 throw new IOException("read failed, socket might closed or timeout, read ret: "
+                         + ret);
             left -= ret;
             if(left != 0)
                 Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left) +
@@ -526,4 +661,18 @@
         bb.order(ByteOrder.nativeOrder());
         return bb.getInt();
     }
+
+    private int fillL2capRxBuffer() throws IOException {
+        mL2capBuffer.rewind();
+        int ret = mSocketIS.read(mL2capBuffer.array());
+        if(ret == -1) {
+            // reached end of stream - return -1
+            mL2capBuffer.limit(0);
+            return -1;
+        }
+        mL2capBuffer.limit(ret);
+        return ret;
+    }
+
+
 }
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 194a53e..2ded4c8 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -76,7 +76,9 @@
             ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid MAS =
             ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
-
+  public static final ParcelUuid SAP =
+            ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
+			
     public static final ParcelUuid BASE_UUID =
             ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
 
@@ -89,7 +91,7 @@
 
     public static final ParcelUuid[] RESERVED_UUIDS = {
         AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
-        ObexObjectPush, PANU, NAP, MAP, MNS, MAS};
+        ObexObjectPush, PANU, NAP, MAP, MNS, MAS, SAP};
 
     public static boolean isAudioSource(ParcelUuid uuid) {
         return uuid.equals(AudioSource);
@@ -143,6 +145,9 @@
     public static boolean isMas(ParcelUuid uuid) {
         return uuid.equals(MAS);
     }
+    public static boolean isSap(ParcelUuid uuid) {
+        return uuid.equals(SAP);
+    }
 
     /**
      * Returns true if ParcelUuid is present in uuidArray
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index dabb1ce..a3eceb5 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -68,7 +68,7 @@
     int getRemoteClass(in BluetoothDevice device);
     ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
     boolean fetchRemoteUuids(in BluetoothDevice device);
-    boolean fetchRemoteMasInstances(in BluetoothDevice device);
+    boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
 
     boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode);
     boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[]
@@ -79,6 +79,8 @@
     boolean setPhonebookAccessPermission(in BluetoothDevice device, int value);
     int getMessageAccessPermission(in BluetoothDevice device);
     boolean setMessageAccessPermission(in BluetoothDevice device, int value);
+    int getSimAccessPermission(in BluetoothDevice device);
+    boolean setSimAccessPermission(in BluetoothDevice device, int value);
 
     void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
 
@@ -101,4 +103,6 @@
 
     // for dumpsys support
     String dump();
+    void onLeServiceUp();
+    void onBrEdrDown();
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 7070bae..72abeaf 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -101,4 +101,7 @@
                             in int srvcInstanceId, in ParcelUuid srvcId,
                             in int charInstanceId, in ParcelUuid charId,
                             in boolean confirm, in byte[] value);
+    void disconnectAll();
+    void unregAll();
+    int numHwTrackFiltersAvailable();
 }
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 91e62ea..cbba9f0 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -67,6 +67,7 @@
     void onReadRemoteRssi(in String address, in int rssi, in int status);
     void onMultiAdvertiseCallback(in int status, boolean isStart,
                                   in AdvertiseSettings advertiseSettings);
+    void onScanManagerErrorCallback(in int errorCode);
     void onConfigureMTU(in String address, in int mtu, in int status);
     void onFoundOrLost(in boolean onFound, in ScanResult scanResult);
 }
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 7411d3f..8d1ce99 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -44,4 +44,6 @@
 
     String getAddress();
     String getName();
+    int updateBleAppCount(IBinder b, boolean enable);
+    boolean isBleAppPresent();
 }
diff --git a/core/java/android/bluetooth/IBluetoothManagerCallback.aidl b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
index 9551086..1385daf 100644
--- a/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
@@ -26,4 +26,5 @@
 interface IBluetoothManagerCallback {
     void onBluetoothServiceUp(in IBluetooth bluetoothService);
     void onBluetoothServiceDown();
-}
\ No newline at end of file
+    void onBrEdrDown();
+}
diff --git a/core/java/android/bluetooth/IBluetoothSap.aidl b/core/java/android/bluetooth/IBluetoothSap.aidl
new file mode 100644
index 0000000..8970639
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothSap.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth SAP service
+ *
+ * {@hide}
+ */
+interface IBluetoothSap {
+    int getState();
+    BluetoothDevice getClient();
+    boolean connect(in BluetoothDevice device);
+    boolean disconnect(in BluetoothDevice device);
+    boolean isConnected(in BluetoothDevice device);
+    List<BluetoothDevice> getConnectedDevices();
+    List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    int getConnectionState(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+}
diff --git a/core/java/android/bluetooth/SdpMasRecord.java b/core/java/android/bluetooth/SdpMasRecord.java
new file mode 100644
index 0000000..fa164c0
--- /dev/null
+++ b/core/java/android/bluetooth/SdpMasRecord.java
@@ -0,0 +1,147 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class SdpMasRecord implements Parcelable {
+    private final int mMasInstanceId;
+    private final int mL2capPsm;
+    private final int mRfcommChannelNumber;
+    private final int mProfileVersion;
+    private final int mSupportedFeatures;
+    private final int mSupportedMessageTypes;
+    private final String mServiceName;
+    public static final class MessageType {
+        public static final int EMAIL    = 0x01;
+        public static final int SMS_GSM  = 0x02;
+        public static final int SMS_CDMA = 0x04;
+        public static final int MMS      = 0x08;
+    }
+
+    public SdpMasRecord(int mas_instance_id,
+                                 int l2cap_psm,
+                                 int rfcomm_channel_number,
+                                 int profile_version,
+                                 int supported_features,
+                                 int supported_message_types,
+                                 String service_name){
+        this.mMasInstanceId = mas_instance_id;
+        this.mL2capPsm = l2cap_psm;
+        this.mRfcommChannelNumber = rfcomm_channel_number;
+        this.mProfileVersion = profile_version;
+        this.mSupportedFeatures = supported_features;
+        this.mSupportedMessageTypes = supported_message_types;
+        this.mServiceName = service_name;
+    }
+
+    public SdpMasRecord(Parcel in){
+        this.mMasInstanceId = in.readInt();
+        this.mL2capPsm = in.readInt();
+        this.mRfcommChannelNumber = in.readInt();
+        this.mProfileVersion = in.readInt();
+        this.mSupportedFeatures = in.readInt();
+        this.mSupportedMessageTypes = in.readInt();
+        this.mServiceName = in.readString();
+    }
+    @Override
+    public int describeContents() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public int getMasInstanceId() {
+        return mMasInstanceId;
+    }
+
+    public int getL2capPsm() {
+        return mL2capPsm;
+    }
+
+    public int getRfcommCannelNumber() {
+        return mRfcommChannelNumber;
+    }
+
+    public int getProfileVersion() {
+        return mProfileVersion;
+    }
+
+    public int getSupportedFeatures() {
+        return mSupportedFeatures;
+    }
+
+    public int getSupportedMessageTypes() {
+        return mSupportedMessageTypes;
+    }
+    
+    public boolean msgSupported(int msg) {
+        return (mSupportedMessageTypes & msg) != 0;
+    }
+    
+    public String getServiceName() {
+        return mServiceName;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+
+        dest.writeInt(this.mMasInstanceId);
+        dest.writeInt(this.mL2capPsm);
+        dest.writeInt(this.mRfcommChannelNumber);
+        dest.writeInt(this.mProfileVersion);
+        dest.writeInt(this.mSupportedFeatures);
+        dest.writeInt(this.mSupportedMessageTypes);
+        dest.writeString(this.mServiceName);
+
+    }
+    @Override
+    public String toString(){
+        String ret = "Bluetooth MAS SDP Record:\n";
+
+        if(mMasInstanceId != -1){
+            ret += "Mas Instance Id: " + mMasInstanceId + "\n";
+        }
+        if(mRfcommChannelNumber != -1){
+            ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
+        }
+        if(mL2capPsm != -1){
+            ret += "L2CAP PSM: " + mL2capPsm + "\n";
+        }
+        if(mServiceName != null){
+            ret += "Service Name: " + mServiceName + "\n";
+        }
+        if(mProfileVersion != -1){
+            ret += "Profile version: " + mProfileVersion + "\n";
+        }
+        if(mSupportedMessageTypes != -1){
+            ret += "Supported msg types: " + mSupportedMessageTypes + "\n";
+        }
+        if(mSupportedFeatures != -1){
+            ret += "Supported features: " + mSupportedFeatures + "\n";
+        }
+        return ret;
+    }
+
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        public SdpMasRecord createFromParcel(Parcel in) {
+            return new SdpMasRecord(in);
+        }
+        public SdpRecord[] newArray(int size) {
+            return new SdpRecord[size];
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/SdpMnsRecord.java b/core/java/android/bluetooth/SdpMnsRecord.java
new file mode 100644
index 0000000..c02bb5a
--- /dev/null
+++ b/core/java/android/bluetooth/SdpMnsRecord.java
@@ -0,0 +1,112 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class SdpMnsRecord implements Parcelable {
+    private final int mL2capPsm;
+    private final int mRfcommChannelNumber;
+    private final int mSupportedFeatures;
+    private final int mProfileVersion;
+    private final String mServiceName;
+
+    public SdpMnsRecord(int l2cap_psm,
+            int rfcomm_channel_number,
+            int profile_version,
+            int supported_features,
+            String service_name){
+        this.mL2capPsm = l2cap_psm;
+        this.mRfcommChannelNumber = rfcomm_channel_number;
+        this.mSupportedFeatures = supported_features;
+        this.mServiceName = service_name;
+        this.mProfileVersion = profile_version;
+    }
+
+    public SdpMnsRecord(Parcel in){
+           this.mRfcommChannelNumber = in.readInt();
+           this.mL2capPsm = in.readInt();
+           this.mServiceName = in.readString();
+           this.mSupportedFeatures = in.readInt();
+           this.mProfileVersion = in.readInt();
+    }
+    @Override
+    public int describeContents() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+
+    public int getL2capPsm() {
+        return mL2capPsm;
+    }
+
+    public int getRfcommChannelNumber() {
+        return mRfcommChannelNumber;
+    }
+
+    public int getSupportedFeatures() {
+        return mSupportedFeatures;
+    }
+
+    public String getServiceName() {
+        return mServiceName;
+    }
+
+    public int getProfileVersion() {
+        return mProfileVersion;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRfcommChannelNumber);
+        dest.writeInt(mL2capPsm);
+        dest.writeString(mServiceName);
+        dest.writeInt(mSupportedFeatures);
+        dest.writeInt(mProfileVersion);
+    }
+
+    public String toString(){
+        String ret = "Bluetooth MNS SDP Record:\n";
+
+        if(mRfcommChannelNumber != -1){
+            ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
+        }
+        if(mL2capPsm != -1){
+            ret += "L2CAP PSM: " + mL2capPsm + "\n";
+        }
+        if(mServiceName != null){
+            ret += "Service Name: " + mServiceName + "\n";
+        }
+        if(mSupportedFeatures != -1){
+            ret += "Supported features: " + mSupportedFeatures + "\n";
+        }
+        if(mProfileVersion != -1){
+            ret += "Profile_version: " + mProfileVersion+"\n";
+        }
+        return ret;
+    }
+
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        public SdpMnsRecord createFromParcel(Parcel in) {
+            return new SdpMnsRecord(in);
+        }
+        public SdpMnsRecord[] newArray(int size) {
+            return new SdpMnsRecord[size];
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/SdpOppOpsRecord.java b/core/java/android/bluetooth/SdpOppOpsRecord.java
new file mode 100644
index 0000000..e0e4007
--- /dev/null
+++ b/core/java/android/bluetooth/SdpOppOpsRecord.java
@@ -0,0 +1,118 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* 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.bluetooth;
+
+import java.util.Arrays;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Data representation of a Object Push Profile Server side SDP record.
+ */
+/** @hide */
+public class SdpOppOpsRecord implements Parcelable {
+
+    private final String mServiceName;
+    private final int mRfcommChannel;
+    private final int mL2capPsm;
+    private final int mProfileVersion;
+    private final byte[] mFormatsList;
+
+    public SdpOppOpsRecord(String serviceName, int rfcommChannel,
+            int l2capPsm, int version, byte[] formatsList) {
+        super();
+        this.mServiceName = serviceName;
+        this.mRfcommChannel = rfcommChannel;
+        this.mL2capPsm = l2capPsm;
+        this.mProfileVersion = version;
+        this.mFormatsList = formatsList;
+    }
+
+    public String getServiceName() {
+        return mServiceName;
+    }
+
+    public int getRfcommChannel() {
+        return mRfcommChannel;
+    }
+
+    public int getL2capPsm() {
+        return mL2capPsm;
+    }
+
+    public int getProfileVersion() {
+        return mProfileVersion;
+    }
+
+    public byte[] getFormatsList() {
+        return mFormatsList;
+    }
+
+    @Override
+    public int describeContents() {
+        /* No special objects */
+        return 0;
+    }
+
+    public SdpOppOpsRecord(Parcel in){
+        this.mRfcommChannel = in.readInt();
+        this.mL2capPsm = in.readInt();
+        this.mProfileVersion = in.readInt();
+        this.mServiceName = in.readString();
+        int arrayLength = in.readInt();
+        if(arrayLength > 0) {
+            byte[] bytes = new byte[arrayLength];
+            in.readByteArray(bytes);
+            this.mFormatsList = bytes;
+        } else {
+            this.mFormatsList = null;
+        }
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRfcommChannel);
+        dest.writeInt(mL2capPsm);
+        dest.writeInt(mProfileVersion);
+        dest.writeString(mServiceName);
+        if(mFormatsList!= null && mFormatsList.length > 0) {
+            dest.writeInt(mFormatsList.length);
+            dest.writeByteArray(mFormatsList);
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
+    public String toString(){
+        StringBuilder sb = new StringBuilder("Bluetooth OPP Server SDP Record:\n");
+        sb.append("  RFCOMM Chan Number: ").append(mRfcommChannel);
+        sb.append("\n  L2CAP PSM: ").append(mL2capPsm);
+        sb.append("\n  Profile version: ").append(mProfileVersion);
+        sb.append("\n  Service Name: ").append(mServiceName);
+        sb.append("\n  Formats List: ").append(Arrays.toString(mFormatsList));
+        return sb.toString();
+    }
+
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        public SdpOppOpsRecord createFromParcel(Parcel in) {
+            return new SdpOppOpsRecord(in);
+        }
+        public SdpOppOpsRecord[] newArray(int size) {
+            return new SdpOppOpsRecord[size];
+        }
+    };
+
+}
diff --git a/core/java/android/bluetooth/SdpPseRecord.java b/core/java/android/bluetooth/SdpPseRecord.java
new file mode 100644
index 0000000..2c159cc
--- /dev/null
+++ b/core/java/android/bluetooth/SdpPseRecord.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class SdpPseRecord implements Parcelable {
+    private final int mL2capPsm;
+    private final int mRfcommChannelNumber;
+    private final int mProfileVersion;
+    private final int mSupportedFeatures;
+    private final int mSupportedRepositories;
+    private final String mServiceName;
+
+    public SdpPseRecord(int l2cap_psm,
+            int rfcomm_channel_number,
+            int profile_version,
+            int supported_features,
+            int supported_repositories,
+            String service_name){
+        this.mL2capPsm = l2cap_psm;
+        this.mRfcommChannelNumber = rfcomm_channel_number;
+        this.mProfileVersion = profile_version;
+        this.mSupportedFeatures = supported_features;
+        this.mSupportedRepositories = supported_repositories;
+        this.mServiceName = service_name;
+    }
+
+    public SdpPseRecord(Parcel in){
+           this.mRfcommChannelNumber = in.readInt();
+           this.mL2capPsm = in.readInt();
+           this.mProfileVersion = in.readInt();
+           this.mSupportedFeatures = in.readInt();
+           this.mSupportedRepositories = in.readInt();
+           this.mServiceName = in.readString();
+    }
+    @Override
+    public int describeContents() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public int getL2capPsm() {
+        return mL2capPsm;
+    }
+
+    public int getRfcommChannelNumber() {
+        return mRfcommChannelNumber;
+    }
+
+    public int getSupportedFeatures() {
+        return mSupportedFeatures;
+    }
+
+    public String getServiceName() {
+        return mServiceName;
+    }
+
+    public int getProfileVersion() {
+        return mProfileVersion;
+    }
+
+    public int getSupportedRepositories() {
+        return mSupportedRepositories;
+    }
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRfcommChannelNumber);
+        dest.writeInt(mL2capPsm);
+        dest.writeInt(mProfileVersion);
+        dest.writeInt(mSupportedFeatures);
+        dest.writeInt(mSupportedRepositories);
+        dest.writeString(mServiceName);
+
+    }
+
+    public String toString(){
+        String ret = "Bluetooth MNS SDP Record:\n";
+
+        if(mRfcommChannelNumber != -1){
+            ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
+        }
+        if(mL2capPsm != -1){
+            ret += "L2CAP PSM: " + mL2capPsm + "\n";
+        }
+        if(mProfileVersion != -1){
+            ret += "profile version: " + mProfileVersion + "\n";
+        }
+        if(mServiceName != null){
+            ret += "Service Name: " + mServiceName + "\n";
+        }
+        if(mSupportedFeatures != -1){
+            ret += "Supported features: " + mSupportedFeatures + "\n";
+        }
+        if(mSupportedRepositories != -1){
+            ret += "Supported repositories: " + mSupportedRepositories + "\n";
+        }
+
+        return ret;
+    }
+
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        public SdpPseRecord createFromParcel(Parcel in) {
+            return new SdpPseRecord(in);
+        }
+        public SdpPseRecord[] newArray(int size) {
+            return new SdpPseRecord[size];
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/SdpRecord.java b/core/java/android/bluetooth/SdpRecord.java
new file mode 100644
index 0000000..6f1065e
--- /dev/null
+++ b/core/java/android/bluetooth/SdpRecord.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2015 Samsung System LSI
+* 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/** @hide */
+public class SdpRecord implements Parcelable{
+
+    private final byte[] mRawData;
+    private final int mRawSize;
+
+    @Override
+    public String toString() {
+        return "BluetoothSdpRecord [rawData=" + Arrays.toString(mRawData)
+                + ", rawSize=" + mRawSize + "]";
+    }
+
+    public SdpRecord(int size_record, byte[] record){
+        this.mRawData = record;
+        this.mRawSize = size_record;
+    }
+
+    public SdpRecord(Parcel in){
+        this.mRawSize = in.readInt();
+        this.mRawData = new byte[mRawSize];
+        in.readByteArray(this.mRawData);
+
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(this.mRawSize);
+        dest.writeByteArray(this.mRawData);
+
+
+    }
+    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+        public SdpRecord createFromParcel(Parcel in) {
+            return new SdpRecord(in);
+        }
+
+        public SdpRecord[] newArray(int size) {
+            return new SdpRecord[size];
+        }
+    };
+
+    public byte[] getRawData() {
+        return mRawData;
+    }
+
+    public int getRawSize() {
+        return mRawSize;
+    }
+}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 93ea299..9c3f3f1 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -128,6 +128,16 @@
                         ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
                 return;
             }
+            if (!isHardwareResourcesAvailableForScan(settings)) {
+                postCallbackError(callback,
+                        ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES);
+                return;
+            }
+            if (!isSettingsAndFilterComboAllowed(settings, filters)) {
+                postCallbackError(callback,
+                        ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
+                return;
+            }
             BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
                     settings, callback, resultStorages);
             wrapper.startRegisteration();
@@ -371,6 +381,18 @@
                 }
             });
         }
+
+        @Override
+        public void onScanManagerErrorCallback(final int errorCode) {
+            if (VDBG) {
+                Log.d(TAG, "onScanManagerErrorCallback() - errorCode = " + errorCode);
+            }
+            synchronized (this) {
+                if (mClientIf <= 0)
+                    return;
+            }
+            postCallbackError(mScanCallback, errorCode);
+        }
     }
 
     private void postCallbackError(final ScanCallback callback, final int errorCode) {
@@ -394,4 +416,33 @@
         }
         return false;
     }
+
+    private boolean isSettingsAndFilterComboAllowed(ScanSettings settings,
+                        List <ScanFilter> filterList) {
+        final int callbackType = settings.getCallbackType();
+        // If onlost/onfound is requested, a non-empty filter is expected
+        if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH
+                        | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) {
+            if (filterList == null) {
+                return false;
+            }
+            for (ScanFilter filter : filterList) {
+                if (filter.isAllFieldsEmpty()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) {
+        final int callbackType = settings.getCallbackType();
+        if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
+                || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
+            // For onlost/onfound, we required hw support be available
+            return (mBluetoothAdapter.isOffloadedFilteringSupported() &&
+                    mBluetoothAdapter.isHardwareTrackingFiltersAvailable());
+        }
+        return true;
+    }
 }
diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java
index 4916bd9..c40256b 100644
--- a/core/java/android/bluetooth/le/BluetoothLeUtils.java
+++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java
@@ -132,7 +132,7 @@
      *             {@link BluetoothAdapter#STATE_ON}.
      */
     static void checkAdapterStateOn(BluetoothAdapter adapter) {
-        if (adapter == null || adapter.getState() != BluetoothAdapter.STATE_ON) {
+        if (adapter == null || !adapter.isLeEnabled()) {//adapter.getState() != BluetoothAdapter.STATE_ON) {
             throw new IllegalStateException("BT Adapter is not turned ON");
         }
     }
diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java
index 05782a8..61b2e78 100644
--- a/core/java/android/bluetooth/le/ScanCallback.java
+++ b/core/java/android/bluetooth/le/ScanCallback.java
@@ -45,10 +45,18 @@
     public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4;
 
     /**
+     * Fails to start scan as it is out of hardware resources.
+     * @hide
+     */
+    public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5;
+
+    /**
      * Callback when a BLE advertisement has been found.
      *
-     * @param callbackType Determines how this callback was triggered. Currently could only be
-     *            {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES}.
+     * @param callbackType Determines how this callback was triggered. Could be one of
+     *            {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES},
+     *            {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH} or
+     *            {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST}
      * @param result A Bluetooth LE scan result.
      */
     public void onScanResult(int callbackType, ScanResult result) {
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 5025218..92a3817 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -67,6 +67,8 @@
     private final byte[] mManufacturerData;
     @Nullable
     private final byte[] mManufacturerDataMask;
+    private static final ScanFilter EMPTY = new ScanFilter.Builder().build() ;
+
 
     private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
             ParcelUuid uuidMask, ParcelUuid serviceDataUuid,
@@ -410,6 +412,14 @@
     }
 
     /**
+     * Checks if the scanfilter is empty
+     * @hide
+     */
+    public boolean isAllFieldsEmpty() {
+        return EMPTY.equals(this);
+    }
+
+    /**
      * Builder class for {@link ScanFilter}.
      */
     public static final class Builder {
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 0106686..31d7963 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -59,24 +59,52 @@
     /**
      * A result callback is only triggered for the first advertisement packet received that matches
      * the filter criteria.
-     *
-     * @hide
      */
-    @SystemApi
     public static final int CALLBACK_TYPE_FIRST_MATCH = 2;
 
     /**
      * Receive a callback when advertisements are no longer received from a device that has been
      * previously reported by a first match callback.
-     *
-     * @hide
      */
-    @SystemApi
     public static final int CALLBACK_TYPE_MATCH_LOST = 4;
 
+
     /**
-     * Request full scan results which contain the device, rssi, advertising data, scan response as
-     * well as the scan timestamp.
+     * Determines how many advertisements to match per filter, as this is scarce hw resource
+     */
+    /**
+     * Match one advertisement per filter
+     */
+    public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1;
+
+    /**
+     * Match few advertisement per filter, depends on current capability and availibility of
+     * the resources in hw
+     */
+    public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2;
+
+    /**
+     * Match as many advertisement per filter as hw could allow, depends on current
+     * capability and availibility of the resources in hw
+     */
+    public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3;
+
+
+    /**
+     * In Aggressive mode, hw will determine a match sooner even with feeble signal strength
+     * and few number of sightings/match in a duration.
+     */
+    public static final int MATCH_MODE_AGGRESSIVE = 1;
+
+    /**
+     * For sticky mode, higher threshold of signal strength and sightings is required
+     * before reporting by hw
+     */
+    public static final int MATCH_MODE_STICKY = 2;
+
+    /**
+     * Request full scan results which contain the device, rssi, advertising data, scan response
+     * as well as the scan timestamp.
      *
      * @hide
      */
@@ -106,6 +134,10 @@
     // Time of delay for reporting the scan result
     private long mReportDelayMillis;
 
+    private int mMatchMode;
+
+    private int mNumOfMatchesPerFilter;
+
     public int getScanMode() {
         return mScanMode;
     }
@@ -119,6 +151,20 @@
     }
 
     /**
+     * @hide
+     */
+    public int getMatchMode() {
+        return mMatchMode;
+    }
+
+    /**
+     * @hide
+     */
+    public int getNumOfMatches() {
+        return mNumOfMatchesPerFilter;
+    }
+
+    /**
      * Returns report delay timestamp based on the device clock.
      */
     public long getReportDelayMillis() {
@@ -126,11 +172,13 @@
     }
 
     private ScanSettings(int scanMode, int callbackType, int scanResultType,
-            long reportDelayMillis) {
+            long reportDelayMillis, int matchMode, int numOfMatchesPerFilter) {
         mScanMode = scanMode;
         mCallbackType = callbackType;
         mScanResultType = scanResultType;
         mReportDelayMillis = reportDelayMillis;
+        mNumOfMatchesPerFilter = numOfMatchesPerFilter;
+        mMatchMode = numOfMatchesPerFilter;
     }
 
     private ScanSettings(Parcel in) {
@@ -138,6 +186,8 @@
         mCallbackType = in.readInt();
         mScanResultType = in.readInt();
         mReportDelayMillis = in.readLong();
+        mMatchMode = in.readInt();
+        mNumOfMatchesPerFilter = in.readInt();
     }
 
     @Override
@@ -146,6 +196,8 @@
         dest.writeInt(mCallbackType);
         dest.writeInt(mScanResultType);
         dest.writeLong(mReportDelayMillis);
+        dest.writeInt(mMatchMode);
+        dest.writeInt(mNumOfMatchesPerFilter);
     }
 
     @Override
@@ -174,7 +226,8 @@
         private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES;
         private int mScanResultType = SCAN_RESULT_TYPE_FULL;
         private long mReportDelayMillis = 0;
-
+        private int mMatchMode = MATCH_MODE_AGGRESSIVE;
+        private int mNumOfMatchesPerFilter  = MATCH_NUM_ONE_ADVERTISEMENT;
         /**
          * Set scan mode for Bluetooth LE scan.
          *
@@ -255,11 +308,46 @@
         }
 
         /**
+         * Set the number of matches for Bluetooth LE scan filters hardware match
+         *
+         * @param numOfMatches The num of matches can be one of
+         *              {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} or
+         *              {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or
+         *              {@link ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT}
+         * @throws IllegalArgumentException If the {@code matchMode} is invalid.
+         */
+        public Builder setNumOfMatches(int numOfMatches) {
+            if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT
+                    || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) {
+                throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches);
+            }
+            mNumOfMatchesPerFilter = numOfMatches;
+            return this;
+        }
+
+        /**
+         * Set match mode for Bluetooth LE scan filters hardware match
+         *
+         * @param matchMode The match mode can be one of
+         *              {@link ScanSettings#MATCH_MODE_AGGRESSIVE} or
+         *              {@link ScanSettings#MATCH_MODE_STICKY}
+         * @throws IllegalArgumentException If the {@code matchMode} is invalid.
+         */
+        public Builder setMatchMode(int matchMode) {
+            if (matchMode < MATCH_MODE_AGGRESSIVE
+                    || matchMode > MATCH_MODE_STICKY) {
+                throw new IllegalArgumentException("invalid matchMode " + matchMode);
+            }
+            mMatchMode = matchMode;
+            return this;
+        }
+
+        /**
          * Build {@link ScanSettings}.
          */
         public ScanSettings build() {
             return new ScanSettings(mScanMode, mCallbackType, mScanResultType,
-                    mReportDelayMillis);
+                    mReportDelayMillis, mMatchMode, mNumOfMatchesPerFilter);
         }
     }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 26735a6..d689ce9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2116,6 +2116,7 @@
             AUDIO_SERVICE,
             MEDIA_ROUTER_SERVICE,
             TELEPHONY_SERVICE,
+            CARRIER_CONFIG_SERVICE,
             TELECOM_SERVICE,
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
@@ -2248,6 +2249,8 @@
      * @see android.telephony.TelephonyManager
      * @see #TELEPHONY_SUBSCRIPTION_SERVICE
      * @see android.telephony.SubscriptionManager
+     * @see #CARRIER_CONFIG_SERVICE
+     * @see android.telephony.CarrierConfigManager
      * @see #INPUT_METHOD_SERVICE
      * @see android.view.inputmethod.InputMethodManager
      * @see #UI_MODE_SERVICE
@@ -2612,6 +2615,15 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.telephony.CarrierConfigManager} for reading carrier configuration values.
+     *
+     * @see #getSystemService
+     * @see android.telephony.CarrierConfigManager
+     */
+    public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.text.ClipboardManager} for accessing and modifying
      * the contents of the global clipboard.
      *
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a00246f..6359f08 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,14 +100,33 @@
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
 
     /**
-     * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any
-     * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
-     *
-     * @hide
+     * The device has connected to a network that has presented a captive
+     * portal, which is blocking Internet connectivity. The user was presented
+     * with a notification that network sign in is required,
+     * and the user invoked the notification's action indicating they
+     * desire to sign in to the network. Apps handling this action should
+     * facilitate signing in to the network. This action includes a
+     * {@link Network} typed extra called {@link #EXTRA_NETWORK} that represents
+     * the network presenting the captive portal; all communication with the
+     * captive portal must be done using this {@code Network} object.
+     * <p/>
+     * When the app handling this action believes the user has signed in to
+     * the network and the captive portal has been dismissed, the app should call
+     * {@link #reportCaptivePortalDismissed} so the system can reevaluate the network.
+     * If reevaluation finds the network no longer subject to a captive portal,
+     * the network may become the default active data network.
+     * <p/>
+     * When the app handling this action believes the user explicitly wants
+     * to ignore the captive portal and the network, the app should call
+     * {@link #ignoreNetworkWithCaptivePortal}.
+     * <p/>
+     * Note that this action includes a {@code String} extra named
+     * {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} that must
+     * be passed in to {@link #reportCaptivePortalDismissed} and
+     * {@link #ignoreNetworkWithCaptivePortal}.
      */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String CONNECTIVITY_ACTION_IMMEDIATE =
-            "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE";
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
 
     /**
      * The lookup key for a {@link NetworkInfo} object. Retrieve with
@@ -115,8 +134,7 @@
      *
      * @deprecated Since {@link NetworkInfo} can vary based on UID, applications
      *             should always obtain network information through
-     *             {@link #getActiveNetworkInfo()} or
-     *             {@link #getAllNetworkInfo()}.
+     *             {@link #getActiveNetworkInfo()}.
      * @see #EXTRA_NETWORK_TYPE
      */
     @Deprecated
@@ -124,8 +142,6 @@
 
     /**
      * Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast.
-     * Can be used with {@link #getNetworkInfo(int)} to get {@link NetworkInfo}
-     * state based on the calling application.
      *
      * @see android.content.Intent#getIntExtra(String, int)
      */
@@ -175,6 +191,15 @@
     public static final String EXTRA_INET_CONDITION = "inetCondition";
 
     /**
+     * The lookup key for a string that is sent out with
+     * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN}. This string must be
+     * passed in to {@link #reportCaptivePortalDismissed} and
+     * {@link #ignoreNetworkWithCaptivePortal}. Retrieve it with
+     * {@link android.content.Intent#getStringExtra(String)}.
+     */
+    public static final String EXTRA_CAPTIVE_PORTAL_TOKEN = "captivePortalToken";
+
+    /**
      * Broadcast action to indicate the change of data activity status
      * (idle or active) on a network in a recent period.
      * The network becomes active when data transmission is started, or
@@ -588,9 +613,9 @@
      * network.
      *
      * @return a {@link NetworkInfo} object for the current default network
-     *        or {@code null} if no network default network is currently active
+     *        or {@code null} if no default network is currently active
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public NetworkInfo getActiveNetworkInfo() {
@@ -602,6 +627,27 @@
     }
 
     /**
+     * Returns a {@link Network} object corresponding to the currently active
+     * default data network.  In the event that the current active default data
+     * network disconnects, the returned {@code Network} object will no longer
+     * be usable.  This will return {@code null} when there is no default
+     * network.
+     *
+     * @return a {@link Network} object for the current default network or
+     *        {@code null} if no default network is currently active
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     */
+    public Network getActiveNetwork() {
+        try {
+            return mService.getActiveNetwork();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
@@ -634,6 +680,10 @@
      *
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @deprecated This method does not support multiple connected networks
+     *             of the same type. Use {@link #getAllNetworks} and
+     *             {@link #getNetworkInfo(android.net.Network)} instead.
      */
     public NetworkInfo getNetworkInfo(int networkType) {
         try {
@@ -673,6 +723,10 @@
      *
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @deprecated This method does not support multiple connected networks
+     *             of the same type. Use {@link #getAllNetworks} and
+     *             {@link #getNetworkInfo(android.net.Network)} instead.
      */
     public NetworkInfo[] getAllNetworkInfo() {
         try {
@@ -690,6 +744,9 @@
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @hide
+     * @deprecated This method does not support multiple connected networks
+     *             of the same type. Use {@link #getAllNetworks} and
+     *             {@link #getNetworkInfo(android.net.Network)} instead.
      */
     public Network getNetworkForType(int networkType) {
         try {
@@ -737,9 +794,9 @@
      * network.
      *
      * @return a {@link NetworkInfo} object for the current default network
-     *        or {@code null} if no network default network is currently active
+     *        or {@code null} if no default network is currently active
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * {@hide}
@@ -759,7 +816,7 @@
      *        for the current default network, or {@code null} if there
      *        is no current default network.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -779,9 +836,13 @@
      *        for the given networkType, or {@code null} if there is
      *        no current default network.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
+     * @deprecated This method does not support multiple connected networks
+     *             of the same type. Use {@link #getAllNetworks},
+     *             {@link #getNetworkInfo(android.net.Network)}, and
+     *             {@link #getLinkProperties(android.net.Network)} instead.
      */
     public LinkProperties getLinkProperties(int networkType) {
         try {
@@ -822,48 +883,6 @@
     }
 
     /**
-     * Tells each network type to set its radio power state as directed.
-     *
-     * @param turnOn a boolean, {@code true} to turn the radios on,
-     *        {@code false} to turn them off.
-     * @return a boolean, {@code true} indicating success.  All network types
-     *        will be tried, even if some fail.
-     *
-     * <p>This method requires the call to hold the permission
-     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
-     * {@hide}
-     */
-// TODO - check for any callers and remove
-//    public boolean setRadios(boolean turnOn) {
-//        try {
-//            return mService.setRadios(turnOn);
-//        } catch (RemoteException e) {
-//            return false;
-//        }
-//    }
-
-    /**
-     * Tells a given networkType to set its radio power state as directed.
-     *
-     * @param networkType the int networkType of interest.
-     * @param turnOn a boolean, {@code true} to turn the radio on,
-     *        {@code} false to turn it off.
-     * @return a boolean, {@code true} indicating success.
-     *
-     * <p>This method requires the call to hold the permission
-     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
-     * {@hide}
-     */
-// TODO - check for any callers and remove
-//    public boolean setRadio(int networkType, boolean turnOn) {
-//        try {
-//            return mService.setRadio(networkType, turnOn);
-//        } catch (RemoteException e) {
-//            return false;
-//        }
-//    }
-
-    /**
      * Tells the underlying networking system that the caller wants to
      * begin using the named feature. The interpretation of {@code feature}
      * is completely up to each networking implementation.
@@ -1201,7 +1220,7 @@
      * @return {@code true} on success, {@code false} on failure
      *
      * @deprecated Deprecated in favor of the {@link #requestNetwork},
-     *             {@link #setProcessDefaultNetwork} and {@link Network#getSocketFactory} api.
+     *             {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} api.
      */
     public boolean requestRouteToHost(int networkType, int hostAddress) {
         return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress));
@@ -1219,7 +1238,7 @@
      * @return {@code true} on success, {@code false} on failure
      * @hide
      * @deprecated Deprecated in favor of the {@link #requestNetwork} and
-     *             {@link #setProcessDefaultNetwork} api.
+     *             {@link #bindProcessToNetwork} api.
      */
     public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
         try {
@@ -1272,7 +1291,7 @@
      * network is active. Quota status can change rapidly, so these values
      * shouldn't be cached.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      *
      * @hide
@@ -1344,7 +1363,7 @@
      * listener.
      * <p>
      * If the process default network has been set with
-     * {@link ConnectivityManager#setProcessDefaultNetwork} this function will not
+     * {@link ConnectivityManager#bindProcessToNetwork} this function will not
      * reflect the process's default, but the system default.
      *
      * @param l The listener to be told when the network is active.
@@ -1429,11 +1448,20 @@
      *               situations where a Context pointer is unavailable.
      * @hide
      */
-    public static ConnectivityManager getInstance() {
-        if (sInstance == null) {
+    static ConnectivityManager getInstanceOrNull() {
+        return sInstance;
+    }
+
+    /**
+     * @deprecated - use getSystemService. This is a kludge to support static access in certain
+     *               situations where a Context pointer is unavailable.
+     * @hide
+     */
+    private static ConnectivityManager getInstance() {
+        if (getInstanceOrNull() == null) {
             throw new IllegalStateException("No ConnectivityManager yet constructed");
         }
-        return sInstance;
+        return getInstanceOrNull();
     }
 
     /**
@@ -1442,7 +1470,7 @@
      *
      * @return an array of 0 or more Strings of tetherable interface names.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1459,7 +1487,7 @@
      *
      * @return an array of 0 or more String of currently tethered interface names.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1482,7 +1510,7 @@
      * @return an array of 0 or more String indicating the interface names
      *        which failed to tether.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1520,7 +1548,7 @@
      * @param iface the interface name to tether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
@@ -1538,7 +1566,7 @@
      * @param iface the interface name to untether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
@@ -1557,7 +1585,7 @@
      *
      * @return a boolean - {@code true} indicating Tethering is supported.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1577,7 +1605,7 @@
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable usb interfaces.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1597,7 +1625,7 @@
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable wifi interfaces.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1617,7 +1645,7 @@
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable bluetooth interfaces.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1639,7 +1667,7 @@
      * @param enable a boolean - {@code true} to enable tethering
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
      * {@hide}
      */
@@ -1682,7 +1710,7 @@
      * @return error The error code of the last error tethering or untethering the named
      *               interface
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
@@ -1701,7 +1729,7 @@
      * @param networkType The type of network you want to report on
      * @param percentage The quality of the connection 0 is bad, 100 is good
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#STATUS_BAR}.
      * {@hide}
      */
@@ -1720,10 +1748,109 @@
      *
      * @param network The {@link Network} the application was attempting to use
      *                or {@code null} to indicate the current default network.
+     * @deprecated Use {@link #reportNetworkConnectivity} which allows reporting both
+     *             working and non-working connectivity.
      */
     public void reportBadNetwork(Network network) {
         try {
-            mService.reportBadNetwork(network);
+            // One of these will be ignored because it matches system's current state.
+            // The other will trigger the necessary reevaluation.
+            mService.reportNetworkConnectivity(network, true);
+            mService.reportNetworkConnectivity(network, false);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Report to the framework whether a network has working connectivity.
+     * This provides a hint to the system that a particular network is providing
+     * working connectivity or not.  In response the framework may re-evaluate
+     * the network's connectivity and might take further action thereafter.
+     *
+     * @param network The {@link Network} the application was attempting to use
+     *                or {@code null} to indicate the current default network.
+     * @param hasConnectivity {@code true} if the application was able to successfully access the
+     *                        Internet using {@code network} or {@code false} if not.
+     */
+    public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+        try {
+            mService.reportNetworkConnectivity(network, hasConnectivity);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@hide} */
+    public static final int CAPTIVE_PORTAL_APP_RETURN_DISMISSED    = 0;
+    /** {@hide} */
+    public static final int CAPTIVE_PORTAL_APP_RETURN_UNWANTED     = 1;
+    /** {@hide} */
+    public static final int CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS = 2;
+
+    /**
+     * Called by an app handling the {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN}
+     * action to indicate to the system that the captive portal has been
+     * dismissed.  In response the framework will re-evaluate the network's
+     * connectivity and might take further action thereafter.
+     *
+     * @param network The {@link Network} object passed via
+     *                {@link #EXTRA_NETWORK} with the
+     *                {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} action.
+     * @param actionToken The {@code String} passed via
+     *                    {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} with the
+     *                    {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} action.
+     */
+    public void reportCaptivePortalDismissed(Network network, String actionToken) {
+        try {
+            mService.captivePortalAppResponse(network, CAPTIVE_PORTAL_APP_RETURN_DISMISSED,
+                    actionToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Called by an app handling the {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN}
+     * action to indicate that the user does not want to pursue signing in to
+     * captive portal and the system should continue to prefer other networks
+     * without captive portals for use as the default active data network.  The
+     * system will not retest the network for a captive portal so as to avoid
+     * disturbing the user with further sign in to network notifications.
+     *
+     * @param network The {@link Network} object passed via
+     *                {@link #EXTRA_NETWORK} with the
+     *                {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} action.
+     * @param actionToken The {@code String} passed via
+     *                    {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} with the
+     *                    {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} action.
+     */
+    public void ignoreNetworkWithCaptivePortal(Network network, String actionToken) {
+        try {
+            mService.captivePortalAppResponse(network, CAPTIVE_PORTAL_APP_RETURN_UNWANTED,
+                    actionToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Called by an app handling the {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN}
+     * action to indicate the user wants to use this network as is, even though
+     * the captive portal is still in place.  The system will treat the network
+     * as if it did not have a captive portal when selecting the network to use
+     * as the default active data network. This may result in this network
+     * becoming the default active data network, which could disrupt network
+     * connectivity for apps because the captive portal is still in place.
+     *
+     * @param network The {@link Network} object passed via
+     *                {@link #EXTRA_NETWORK} with the
+     *                {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} action.
+     * @param actionToken The {@code String} passed via
+     *                    {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} with the
+     *                    {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} action.
+     * @hide
+     */
+    public void useNetworkWithCaptivePortal(Network network, String actionToken) {
+        try {
+            mService.captivePortalAppResponse(network, CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS,
+                    actionToken);
         } catch (RemoteException e) {
         }
     }
@@ -1737,7 +1864,7 @@
      * @param p The a {@link ProxyInfo} object defining the new global
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * android.Manifest.permission#CONNECTIVITY_INTERNAL.
      * @hide
      */
@@ -1754,7 +1881,7 @@
      * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
      *        if no global HTTP proxy is set.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
@@ -1769,15 +1896,14 @@
     /**
      * Get the current default HTTP proxy settings.  If a global proxy is set it will be returned,
      * otherwise if this process is bound to a {@link Network} using
-     * {@link #setProcessDefaultNetwork} then that {@code Network}'s proxy is returned, otherwise
+     * {@link #bindProcessToNetwork} then that {@code Network}'s proxy is returned, otherwise
      * the default network's proxy is returned.
      *
      * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
      *        HTTP proxy is active.
-     * @hide
      */
     public ProxyInfo getDefaultProxy() {
-        final Network network = getProcessDefaultNetwork();
+        final Network network = getBoundNetworkForProcess();
         if (network != null) {
             final ProxyInfo globalProxy = getGlobalProxy();
             if (globalProxy != null) return globalProxy;
@@ -1803,7 +1929,7 @@
      * @param networkType The network type we'd like to check
      * @return {@code true} if supported, else {@code false}
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * @hide
      */
@@ -1825,7 +1951,7 @@
      * @return {@code true} if large transfers should be avoided, otherwise
      *        {@code false}.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      */
     public boolean isActiveNetworkMetered() {
@@ -1861,7 +1987,7 @@
      *        in question.
      * @param isCaptivePortal true/false.
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * {@hide}
      */
@@ -1922,6 +2048,7 @@
      * @param networkType
      *
      * {@hide}
+     * @deprecated Doesn't properly deal with multiple connected networks of the same type.
      */
     public void setProvisioningNotificationVisible(boolean visible, int networkType,
             String action) {
@@ -1936,7 +2063,7 @@
      *
      * @param enable whether to enable airplane mode or not
      *
-     * <p>This method requires the call to hold the permission
+     * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
      * @hide
      */
@@ -1961,12 +2088,18 @@
         } catch (RemoteException e) { }
     }
 
-    /** {@hide} */
-    public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+    /**
+     * @hide
+     * Register a NetworkAgent with ConnectivityService.
+     * @return NetID corresponding to NetworkAgent.
+     */
+    public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkMisc misc) {
         try {
-            mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
-        } catch (RemoteException e) { }
+            return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
+        } catch (RemoteException e) {
+            return NETID_UNSET;
+        }
     }
 
     /**
@@ -2337,9 +2470,8 @@
      * successfully finding a network for the applications request.  Retrieve it with
      * {@link android.content.Intent#getParcelableExtra(String)}.
      * <p>
-     * Note that if you intend to invoke {@link #setProcessDefaultNetwork} or
-     * {@link Network#openConnection(java.net.URL)} then you must get a
-     * ConnectivityManager instance before doing so.
+     * Note that if you intend to invoke {@link Network#openConnection(java.net.URL)}
+     * then you must get a ConnectivityManager instance before doing so.
      */
     public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
 
@@ -2428,6 +2560,23 @@
     }
 
     /**
+     * Request connectivityservice to refresh network capabilities for the given
+     * {@link network}. This method returns true if the network is still active, false
+     * otherwise. Notice the method call assumes the caller has registered for
+     * listening NetworkCapabilities updates.
+     *
+     * @param network{@link Network} specifying which network you're interested.
+     * @hide
+     */
+    public boolean requestBwUpdate(Network network) {
+        try {
+            return mService.requestBwUpdate(network);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Unregisters callbacks about and possibly releases networks originating from
      * {@link #requestNetwork} and {@link #registerNetworkCallback} calls.  If the
      * given {@code NetworkCallback} had previously been used with {@code #requestNetwork},
@@ -2458,15 +2607,42 @@
      * Sockets created by Network.getSocketFactory().createSocket() and
      * performing network-specific host name resolutions via
      * {@link Network#getAllByName Network.getAllByName} is preferred to calling
-     * {@code setProcessDefaultNetwork}.
+     * {@code bindProcessToNetwork}.
      *
      * @param network The {@link Network} to bind the current process to, or {@code null} to clear
      *                the current binding.
      * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
      */
+    public boolean bindProcessToNetwork(Network network) {
+        // Forcing callers to call thru non-static function ensures ConnectivityManager
+        // instantiated.
+        return setProcessDefaultNetwork(network);
+    }
+
+    /**
+     * Binds the current process to {@code network}.  All Sockets created in the future
+     * (and not explicitly bound via a bound SocketFactory from
+     * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to
+     * {@code network}.  All host name resolutions will be limited to {@code network} as well.
+     * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to
+     * work and all host name resolutions will fail.  This is by design so an application doesn't
+     * accidentally use Sockets it thinks are still bound to a particular {@link Network}.
+     * To clear binding pass {@code null} for {@code network}.  Using individually bound
+     * Sockets created by Network.getSocketFactory().createSocket() and
+     * performing network-specific host name resolutions via
+     * {@link Network#getAllByName Network.getAllByName} is preferred to calling
+     * {@code setProcessDefaultNetwork}.
+     *
+     * @param network The {@link Network} to bind the current process to, or {@code null} to clear
+     *                the current binding.
+     * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
+     * @deprecated This function can throw {@link IllegalStateException}.  Use
+     *             {@link #bindProcessToNetwork} instead.  {@code bindProcessToNetwork}
+     *             is a direct replacement.
+     */
     public static boolean setProcessDefaultNetwork(Network network) {
         int netId = (network == null) ? NETID_UNSET : network.netId;
-        if (netId == NetworkUtils.getNetworkBoundToProcess()) {
+        if (netId == NetworkUtils.getBoundNetworkForProcess()) {
             return true;
         }
         if (NetworkUtils.bindProcessToNetwork(netId)) {
@@ -2486,19 +2662,34 @@
 
     /**
      * Returns the {@link Network} currently bound to this process via
-     * {@link #setProcessDefaultNetwork}, or {@code null} if no {@link Network} is explicitly bound.
+     * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound.
      *
      * @return {@code Network} to which this process is bound, or {@code null}.
      */
+    public Network getBoundNetworkForProcess() {
+        // Forcing callers to call thru non-static function ensures ConnectivityManager
+        // instantiated.
+        return getProcessDefaultNetwork();
+    }
+
+    /**
+     * Returns the {@link Network} currently bound to this process via
+     * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound.
+     *
+     * @return {@code Network} to which this process is bound, or {@code null}.
+     * @deprecated Using this function can lead to other functions throwing
+     *             {@link IllegalStateException}.  Use {@link #getBoundNetworkForProcess} instead.
+     *             {@code getBoundNetworkForProcess} is a direct replacement.
+     */
     public static Network getProcessDefaultNetwork() {
-        int netId = NetworkUtils.getNetworkBoundToProcess();
+        int netId = NetworkUtils.getBoundNetworkForProcess();
         if (netId == NETID_UNSET) return null;
         return new Network(netId);
     }
 
     /**
      * Binds host resolutions performed by this process to {@code network}.
-     * {@link #setProcessDefaultNetwork} takes precedence over this setting.
+     * {@link #bindProcessToNetwork} takes precedence over this setting.
      *
      * @param network The {@link Network} to bind host resolutions from the current process to, or
      *                {@code null} to clear the current binding.
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index 1b8adc8..73ef78e 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -37,7 +37,7 @@
  * StateMachine that interacts with the native DHCP client and can talk to
  * a controller that also needs to be a StateMachine
  *
- * The Dhcp state machine provides the following features:
+ * The DhcpStateMachine provides the following features:
  * - Wakeup and renewal using the native DHCP client  (which will not renew
  *   on its own when the device is in suspend state and this can lead to device
  *   holding IP address beyond expiry)
@@ -72,11 +72,6 @@
     //Used for sanity check on setting up renewal
     private static final int MIN_RENEWAL_TIME_SECS = 5 * 60;  // 5 minutes
 
-    private enum DhcpAction {
-        START,
-        RENEW
-    };
-
     private final String mInterfaceName;
     private boolean mRegisteredForPreDhcpNotification = false;
 
@@ -99,6 +94,9 @@
      * after pre DHCP action is complete */
     public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = BASE + 7;
 
+    /* Command from ourselves to see if DHCP results are available */
+    private static final int CMD_GET_DHCP_RESULTS           = BASE + 8;
+
     /* Message.arg1 arguments to CMD_POST_DHCP notification */
     public static final int DHCP_SUCCESS = 1;
     public static final int DHCP_FAILURE = 2;
@@ -108,6 +106,7 @@
     private State mWaitBeforeStartState = new WaitBeforeStartState();
     private State mRunningState = new RunningState();
     private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
+    private State mPollingState = new PollingState();
 
     private DhcpStateMachine(Context context, StateMachine controller, String intf) {
         super(TAG);
@@ -139,6 +138,7 @@
         addState(mDefaultState);
             addState(mStoppedState, mDefaultState);
             addState(mWaitBeforeStartState, mDefaultState);
+            addState(mPollingState, mDefaultState);
             addState(mRunningState, mDefaultState);
             addState(mWaitBeforeRenewalState, mDefaultState);
 
@@ -206,6 +206,10 @@
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
+            if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+                Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+            }
+            mDhcpResults = null;
         }
 
         @Override
@@ -219,7 +223,7 @@
                         mController.sendMessage(CMD_PRE_DHCP_ACTION);
                         transitionTo(mWaitBeforeStartState);
                     } else {
-                        if (runDhcp(DhcpAction.START)) {
+                        if (runDhcpStart()) {
                             transitionTo(mRunningState);
                         }
                     }
@@ -247,10 +251,10 @@
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             switch (message.what) {
                 case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    if (runDhcp(DhcpAction.START)) {
+                    if (runDhcpStart()) {
                         transitionTo(mRunningState);
                     } else {
-                        transitionTo(mStoppedState);
+                        transitionTo(mPollingState);
                     }
                     break;
                 case CMD_STOP_DHCP:
@@ -267,6 +271,55 @@
         }
     }
 
+    class PollingState extends State {
+        private static final long MAX_DELAY_SECONDS = 32;
+        private long delaySeconds;
+
+        private void scheduleNextResultsCheck() {
+            sendMessageDelayed(obtainMessage(CMD_GET_DHCP_RESULTS), delaySeconds * 1000);
+            delaySeconds *= 2;
+            if (delaySeconds > MAX_DELAY_SECONDS) {
+                delaySeconds = MAX_DELAY_SECONDS;
+            }
+        }
+
+        @Override
+        public void enter() {
+            if (DBG) Log.d(TAG, "Entering " + getName() + "\n");
+            delaySeconds = 1;
+            scheduleNextResultsCheck();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            boolean retValue = HANDLED;
+            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+            switch (message.what) {
+                case CMD_GET_DHCP_RESULTS:
+                    if (DBG) Log.d(TAG, "GET_DHCP_RESULTS on " + mInterfaceName);
+                    if (dhcpSucceeded()) {
+                        transitionTo(mRunningState);
+                    } else {
+                        scheduleNextResultsCheck();
+                    }
+                    break;
+                case CMD_STOP_DHCP:
+                    transitionTo(mStoppedState);
+                    break;
+                default:
+                    retValue = NOT_HANDLED;
+                    break;
+            }
+            return retValue;
+        }
+
+        @Override
+        public void exit() {
+            if (DBG) Log.d(TAG, "Exiting " + getName() + "\n");
+            removeMessages(CMD_GET_DHCP_RESULTS);
+        }
+    }
+
     class RunningState extends State {
         @Override
         public void enter() {
@@ -280,9 +333,6 @@
             switch (message.what) {
                 case CMD_STOP_DHCP:
                     mAlarmManager.cancel(mDhcpRenewalIntent);
-                    if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-                        Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
-                    }
                     transitionTo(mStoppedState);
                     break;
                 case CMD_RENEW_DHCP:
@@ -292,7 +342,7 @@
                         transitionTo(mWaitBeforeRenewalState);
                         //mDhcpRenewWakeLock is released in WaitBeforeRenewalState
                     } else {
-                        if (!runDhcp(DhcpAction.RENEW)) {
+                        if (!runDhcpRenew()) {
                             transitionTo(mStoppedState);
                         }
                         mDhcpRenewWakeLock.release();
@@ -321,13 +371,10 @@
             switch (message.what) {
                 case CMD_STOP_DHCP:
                     mAlarmManager.cancel(mDhcpRenewalIntent);
-                    if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-                        Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
-                    }
                     transitionTo(mStoppedState);
                     break;
                 case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    if (runDhcp(DhcpAction.RENEW)) {
+                    if (runDhcpRenew()) {
                        transitionTo(mRunningState);
                     } else {
                        transitionTo(mStoppedState);
@@ -348,52 +395,68 @@
         }
     }
 
-    private boolean runDhcp(DhcpAction dhcpAction) {
-        boolean success = false;
+    private boolean dhcpSucceeded() {
         DhcpResults dhcpResults = new DhcpResults();
-
-        if (dhcpAction == DhcpAction.START) {
-            /* Stop any existing DHCP daemon before starting new */
-            NetworkUtils.stopDhcp(mInterfaceName);
-            if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
-            success = NetworkUtils.runDhcp(mInterfaceName, dhcpResults);
-        } else if (dhcpAction == DhcpAction.RENEW) {
-            if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
-            success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpResults);
-            if (success) dhcpResults.updateFromDhcpRequest(mDhcpResults);
+        if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) {
+            return false;
         }
-        if (success) {
-            if (DBG) Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
-            long leaseDuration = dhcpResults.leaseDuration; //int to long conversion
 
-            //Sanity check for renewal
-            if (leaseDuration >= 0) {
-                //TODO: would be good to notify the user that his network configuration is
-                //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
-                if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
-                    leaseDuration = MIN_RENEWAL_TIME_SECS;
-                }
-                //Do it a bit earlier than half the lease duration time
-                //to beat the native DHCP client and avoid extra packets
-                //48% for one hour lease time = 29 minutes
-                mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        SystemClock.elapsedRealtime() +
-                        leaseDuration * 480, //in milliseconds
-                        mDhcpRenewalIntent);
-            } else {
-                //infinite lease time, no renewal needed
+        if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName);
+        long leaseDuration = dhcpResults.leaseDuration; //int to long conversion
+
+        //Sanity check for renewal
+        if (leaseDuration >= 0) {
+            //TODO: would be good to notify the user that his network configuration is
+            //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
+            if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
+                leaseDuration = MIN_RENEWAL_TIME_SECS;
             }
-
-            mDhcpResults = dhcpResults;
-            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults)
-                .sendToTarget();
+            //Do it a bit earlier than half the lease duration time
+            //to beat the native DHCP client and avoid extra packets
+            //48% for one hour lease time = 29 minutes
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() +
+                    leaseDuration * 480, //in milliseconds
+                    mDhcpRenewalIntent);
         } else {
-            Log.e(TAG, "DHCP failed on " + mInterfaceName + ": " +
-                    NetworkUtils.getDhcpError());
-            NetworkUtils.stopDhcp(mInterfaceName);
-            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
-                .sendToTarget();
+            //infinite lease time, no renewal needed
         }
-        return success;
+
+        // Fill in any missing fields in dhcpResults from the previous results.
+        // If mDhcpResults is null (i.e. this is the first server response),
+        // this is a noop.
+        dhcpResults.updateFromDhcpRequest(mDhcpResults);
+        mDhcpResults = dhcpResults;
+        mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults)
+            .sendToTarget();
+        return true;
+    }
+
+    private boolean runDhcpStart() {
+        /* Stop any existing DHCP daemon before starting new */
+        NetworkUtils.stopDhcp(mInterfaceName);
+        mDhcpResults = null;
+
+        if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
+        if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) {
+            Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " +
+                    NetworkUtils.getDhcpError());
+            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+                    .sendToTarget();
+            return false;
+        }
+        return true;
+    }
+
+    private boolean runDhcpRenew() {
+        if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+        if (!NetworkUtils.startDhcpRenew(mInterfaceName) || !dhcpSucceeded()) {
+            Log.e(TAG, "DHCP renew failed on " + mInterfaceName + ": " +
+                    NetworkUtils.getDhcpError());
+            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+                    .sendToTarget();
+            return false;
+        }
+        return true;
     }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d8852f8..6e06aa5 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -42,6 +42,7 @@
 /** {@hide} */
 interface IConnectivityManager
 {
+    Network getActiveNetwork();
     NetworkInfo getActiveNetworkInfo();
     NetworkInfo getActiveNetworkInfoForUid(int uid);
     NetworkInfo getNetworkInfo(int networkType);
@@ -94,7 +95,9 @@
 
     void reportInetCondition(int networkType, int percentage);
 
-    void reportBadNetwork(in Network network);
+    void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
+
+    void captivePortalAppResponse(in Network network, int response, String actionToken);
 
     ProxyInfo getGlobalProxy();
 
@@ -118,8 +121,6 @@
 
     void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal);
 
-    int findConnectionTypeForIface(in String iface);
-
     int checkMobileProvisioning(int suggestedTimeOutMs);
 
     String getMobileProvisioningUrl();
@@ -132,9 +133,11 @@
 
     void registerNetworkFactory(in Messenger messenger, in String name);
 
+    boolean requestBwUpdate(in Network network);
+
     void unregisterNetworkFactory(in Messenger messenger);
 
-    void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+    int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
             in NetworkCapabilities nc, int score, in NetworkMisc misc);
 
     NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 5c12696..4ce9e68 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -51,7 +51,7 @@
  * {@link ConnectivityManager#registerNetworkCallback} calls.
  * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
  * through a targeted {@link SocketFactory} or process-wide via
- * {@link ConnectivityManager#setProcessDefaultNetwork}.
+ * {@link ConnectivityManager#bindProcessToNetwork}.
  */
 public class Network implements Parcelable {
 
@@ -245,7 +245,10 @@
      * @see java.net.URL#openConnection()
      */
     public URLConnection openConnection(URL url) throws IOException {
-        final ConnectivityManager cm = ConnectivityManager.getInstance();
+        final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull();
+        if (cm == null) {
+            throw new IOException("No ConnectivityManager yet constructed, please construct one");
+        }
         // TODO: Should this be optimized to avoid fetching the global proxy for every request?
         ProxyInfo proxyInfo = cm.getGlobalProxy();
         if (proxyInfo == null) {
@@ -272,7 +275,6 @@
      * @throws IllegalArgumentException if the argument proxy is null.
      * @throws IOException if an error occurs while opening the connection.
      * @see java.net.URL#openConnection()
-     * @hide
      */
     public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException {
         if (proxy == null) throw new IllegalArgumentException("proxy is null");
@@ -299,7 +301,7 @@
     /**
      * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the
      * socket will be sent on this {@code Network}, irrespective of any process-wide network binding
-     * set by {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be
+     * set by {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be
      * connected.
      */
     public void bindSocket(DatagramSocket socket) throws IOException {
@@ -316,7 +318,7 @@
     /**
      * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
      * will be sent on this {@code Network}, irrespective of any process-wide network binding set by
-     * {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be connected.
+     * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected.
      */
     public void bindSocket(Socket socket) throws IOException {
         // Apparently, the kernel doesn't update a connected TCP socket's routing upon mark changes.
@@ -338,6 +340,35 @@
         }
     }
 
+    /**
+     * Returns a handle representing this {@code Network}, for use with the NDK API.
+     */
+    public long getNetworkHandle() {
+        // The network handle is explicitly not the same as the netId.
+        //
+        // The netId is an implementation detail which might be changed in the
+        // future, or which alone (i.e. in the absence of some additional
+        // context) might not be sufficient to fully identify a Network.
+        //
+        // As such, the intention is to prevent accidental misuse of the API
+        // that might result if a developer assumed that handles and netIds
+        // were identical and passing a netId to a call expecting a handle
+        // "just worked".  Such accidental misuse, if widely deployed, might
+        // prevent future changes to the semantics of the netId field or
+        // inhibit the expansion of state required for Network objects.
+        //
+        // This extra layer of indirection might be seen as paranoia, and might
+        // never end up being necessary, but the added complexity is trivial.
+        // At some future date it may be desirable to realign the handle with
+        // Multiple Provisioning Domains API recommendations, as made by the
+        // IETF mif working group.
+        //
+        // The HANDLE_MAGIC value MUST be kept in sync with the corresponding
+        // value in the native/android/net.c NDK implementation.
+        final long HANDLE_MAGIC = 0xfacade;
+        return (((long) netId) << 32) | HANDLE_MAGIC;
+    }
+
     // implement the Parcelable interface
     public int describeContents() {
         return 0;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 74d4ac2..c33aa2f 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -42,12 +42,18 @@
  * @hide
  */
 public abstract class NetworkAgent extends Handler {
+    // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown
+    // an exception.
+    public final int netId;
+
     private volatile AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
     private final Context mContext;
     private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
+    private volatile long mLastBwRefreshTime = 0;
+    private static final long BW_REFRESH_MIN_WIN_MS = 500;
 
     private static final int BASE = Protocol.BASE_NETWORK_AGENT;
 
@@ -125,6 +131,13 @@
      */
     public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
 
+    /**
+     * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
+     * the underlying network connection for updated bandwidth information.
+     */
+    public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 9;
+
+
     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
             NetworkCapabilities nc, LinkProperties lp, int score) {
         this(looper, context, logTag, ni, nc, lp, score, null);
@@ -142,7 +155,7 @@
         if (VDBG) log("Registering NetworkAgent");
         ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
-        cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
+        netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
                 new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
     }
 
@@ -186,6 +199,15 @@
                 log("Unhandled Message " + msg);
                 break;
             }
+            case CMD_REQUEST_BANDWIDTH_UPDATE: {
+                if (VDBG) {
+                    log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
+                }
+                if (System.currentTimeMillis() > (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
+                    pollLceData();
+                }
+                break;
+            }
             case CMD_REPORT_NETWORK_STATUS: {
                 if (VDBG) {
                     log("CMD_REPORT_NETWORK_STATUS(" +
@@ -228,6 +250,7 @@
      * Called by the bearer code when it has new NetworkCapabilities data.
      */
     public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
+        mLastBwRefreshTime = System.currentTimeMillis();
         queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED,
                 new NetworkCapabilities(networkCapabilities));
     }
@@ -276,6 +299,13 @@
     abstract protected void unwanted();
 
     /**
+     * Called when ConnectivityService request a bandwidth update. The parent factory
+     * shall try to overwrite this method and produce a bandwidth update if capable.
+     */
+    protected void pollLceData() {
+    }
+
+    /**
      * Called when the system determines the usefulness of this network.
      *
      * Networks claiming internet connectivity will have their internet
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 02fbe73..29dd8ad 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -159,7 +159,7 @@
      * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
      * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
      */
-    public native static int getNetworkBoundToProcess();
+    public native static int getBoundNetworkForProcess();
 
     /**
      * Binds host resolutions performed by this process to the network designated by {@code netId}.
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 3477b02..e07f211 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -44,14 +44,9 @@
     private static final ProxySelector sDefaultProxySelector;
 
     /**
-     * Used to notify an app that's caching the default connection proxy
-     * that either the default connection or its proxy has changed.
-     * The intent will have the following extra value:</p>
-     * <ul>
-     *   <li><em>EXTRA_PROXY_INFO</em> - The ProxyProperties for the proxy.  Non-null,
-     *                                   though if the proxy is undefined the host string
-     *                                   will be empty.
-     * </ul>
+     * Used to notify an app that's caching the proxy that either the default
+     * connection has changed or any connection's proxy has changed. The new
+     * proxy should be queried using {@link ConnectivityManager#getDefaultProxy()}.
      *
      * <p class="note">This is a protected intent that can only be sent by the system
      */
@@ -60,6 +55,11 @@
     /**
      * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
      * It describes the new proxy being used (as a {@link ProxyInfo} object).
+     * @deprecated Because {@code PROXY_CHANGE_ACTION} is sent whenever the proxy
+     * for any network on the system changes, applications should always use
+     * {@link ConnectivityManager#getDefaultProxy()} or
+     * {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()}
+     * to get the proxy for the Network(s) they are using.
      */
     public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
 
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index c26af06..a0e65eb 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -679,7 +679,7 @@
          *
          * By default, all traffic from apps is forwarded through the VPN interface and it is not
          * possible for apps to side-step the VPN. If this method is called, apps may use methods
-         * such as {@link ConnectivityManager#setProcessDefaultNetwork} to instead send/receive
+         * such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive
          * directly over the underlying network or any other network they have permissions for.
          *
          * @return this {@link Builder} object to facilitate chaining of method calls.
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 2df9dbf..dc8e76f 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -446,7 +446,6 @@
                 long start, int duration, Long dataUsage, boolean addForAllUsers) {
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
-            boolean isHidden = false;
 
             TelecomManager tm = null;
             try {
@@ -461,12 +460,6 @@
                     if (address != null) {
                         accountAddress = address.getSchemeSpecificPart();
                     }
-                } else {
-                    // We could not find the account through telecom. For call log entries that
-                    // are added with a phone account which is not registered, we automatically
-                    // mark them as hidden. They are unhidden once the account is registered.
-                    Log.i(LOG_TAG, "Marking call log entry as hidden.");
-                    isHidden = true;
                 }
             }
 
@@ -512,7 +505,6 @@
             values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
             values.put(PHONE_ACCOUNT_ID, accountId);
             values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
-            values.put(PHONE_ACCOUNT_HIDDEN, Integer.valueOf(isHidden ? 1 : 0));
             values.put(NEW, Integer.valueOf(1));
 
             if (callType == MISSED_TYPE) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2647247..7819c73 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2395,8 +2395,6 @@
          * It was about AudioManager's setting and thus affected all the applications which
          * relied on the setting, while this is purely about the vibration setting for incoming
          * calls.
-         *
-         * @hide
          */
         public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
 
@@ -2411,7 +2409,6 @@
          * DTMF tone type played by the dialer when dialing.
          *                 0 = Normal
          *                 1 = Long
-         * @hide
          */
         public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
 
@@ -5838,6 +5835,14 @@
                 "wifi_scan_always_enabled";
 
        /**
+        * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
+        * connectivity.
+        * @hide
+        */
+       public static final String BLE_SCAN_ALWAYS_AVAILABLE =
+               "ble_scan_always_enabled";
+
+       /**
         * Used to save the Wifi_ON state prior to tethering.
         * This state will be checked to restore Wifi after
         * the user turns off tethering.
@@ -6301,6 +6306,9 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
+        /** {@hide} */
+        public static final String
+                BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
 
         /**
          * Get the key that retrieves a bluetooth headset's priority.
@@ -6333,6 +6341,15 @@
         public static final String getBluetoothMapPriorityKey(String address) {
             return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
         }
+
+        /**
+         * Get the key that retrieves a bluetooth map priority.
+         * @hide
+         */
+        public static final String getBluetoothSapPriorityKey(String address) {
+            return BLUETOOTH_SAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+
         /**
          * Scaling factor for normal window animations. Setting to 0 will
          * disable window animations.
@@ -6402,7 +6419,6 @@
         /**
          * Setting to 1 will hide carrier network settings.
          * Default is 0.
-         * @hide
          */
         public static final String HIDE_CARRIER_NETWORK_SETTINGS =
                 "hide_carrier_network_settings";
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 0da4fd5..92119b9 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -254,6 +254,8 @@
          * @param context The context of the app doing the inserting
          * @param voicemail Data to be inserted
          * @return {@link Uri} of the newly inserted {@link Voicemail}
+         *
+         * @hide
          */
         public static Uri insert(Context context, Voicemail voicemail) {
             ContentResolver contentResolver = context.getContentResolver();
@@ -267,6 +269,8 @@
          * @param context The context of the app doing the inserting
          * @param voicemails Data to be inserted
          * @return the number of voicemails inserted
+         *
+         * @hide
          */
         public static int insert(Context context, List<Voicemail> voicemails) {
             ContentResolver contentResolver = context.getContentResolver();
@@ -283,6 +287,8 @@
          * package. By default, a package only has permission to delete voicemails it inserted.
          *
          * @return the number of voicemails deleted
+         *
+         * @hide
          */
         public static int deleteAll(Context context) {
             return context.getContentResolver().delete(
@@ -439,6 +445,8 @@
          * @param configurationState See {@link Status#CONFIGURATION_STATE}
          * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
          * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
+         *
+         * @hide
          */
         public static void setStatus(Context context, PhoneAccountHandle accountHandle,
                 int configurationState, int dataChannelState, int notificationChannelState) {
diff --git a/core/java/android/service/carrier/CarrierConfigService.java b/core/java/android/service/carrier/CarrierConfigService.java
new file mode 100644
index 0000000..1880d16
--- /dev/null
+++ b/core/java/android/service/carrier/CarrierConfigService.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 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.service.carrier;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * A service that sets carrier configuration for telephony services.
+ * <p>
+ * To extend this class, you must declare the service in your manifest file to require the
+ * {@link android.Manifest.permission#BIND_CARRIER_CONFIG_SERVICE} permission and include an intent
+ * filter with the {@link #SERVICE_INTERFACE} action. For example:
+ * </p>
+ *
+ * <pre>{@code
+ * <service android:name=".MyCarrierConfigService"
+ *       android:label="@string/service_name"
+ *       android:permission="android.permission.BIND_CARRIER_CONFIG_SERVICE">
+ *  <intent-filter>
+ *      <action android:name="android.service.carrier.CarrierConfigService" />
+ *  </intent-filter>
+ * </service>
+ * }</pre>
+ */
+public abstract class CarrierConfigService extends Service {
+
+    public static final String SERVICE_INTERFACE = "android.service.carrier.CarrierConfigService";
+
+    private final ICarrierConfigService.Stub mStubWrapper;
+
+    public CarrierConfigService() {
+        mStubWrapper = new ICarrierConfigServiceWrapper();
+    }
+
+    /**
+     * Override this method to set carrier configuration.
+     * <p>
+     * This method will be called by telephony services to get carrier-specific configuration
+     * values. The returned config will be saved by the system until,
+     * <ol>
+     * <li>The carrier app package is updated, or</li>
+     * <li>The carrier app requests a reload with
+     * {@link android.telephony.CarrierConfigManager#reloadCarrierConfigForSubId
+     * reloadCarrierConfigForSubId}.</li>
+     * </ol>
+     * This method can be called after a SIM card loads, which may be before or after boot.
+     * </p>
+     * <p>
+     * This method should not block for a long time. If expensive operations (e.g. network access)
+     * are required, this method can schedule the work and return null. Then, use
+     * {@link android.telephony.CarrierConfigManager#reloadCarrierConfigForSubId
+     * reloadCarrierConfigForSubId} to trigger a reload when the config is ready.
+     * </p>
+     * <p>
+     * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager
+     * CarrierConfigManager}. Any configuration values not set in the returned {@link Bundle} may be
+     * overridden by the system's default configuration service.
+     * </p>
+     *
+     * @param id contains details about the current carrier that can be used do decide what
+     *            configuration values to return.
+     * @return a {@link Bundle} object containing the configuration or null if default values should
+     *         be used.
+     */
+    public abstract Bundle onLoadConfig(CarrierIdentifier id);
+
+    /** @hide */
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            return null;
+        }
+        return mStubWrapper;
+    }
+
+    /**
+     * A wrapper around ICarrierConfigService that forwards calls to implementations of
+     * {@link CarrierConfigService}.
+     *
+     * @hide
+     */
+    private class ICarrierConfigServiceWrapper extends ICarrierConfigService.Stub {
+
+        @Override
+        public Bundle getCarrierConfig(CarrierIdentifier id) {
+            return CarrierConfigService.this.onLoadConfig(id);
+        }
+    }
+}
diff --git a/core/java/android/service/carrier/CarrierIdentifier.aidl b/core/java/android/service/carrier/CarrierIdentifier.aidl
new file mode 100644
index 0000000..48b1398
--- /dev/null
+++ b/core/java/android/service/carrier/CarrierIdentifier.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015, 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.service.carrier;
+
+parcelable CarrierIdentifier;
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
new file mode 100644
index 0000000..495fea6
--- /dev/null
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2015, 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.service.carrier;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Used to pass info to CarrierConfigService implementations so they can decide what values to
+ * return.
+ */
+public class CarrierIdentifier implements Parcelable {
+
+    /** Used to create a {@link CarrierIdentifier} from a {@link Parcel}. */
+    public static final Creator<CarrierIdentifier> CREATOR = new Creator<CarrierIdentifier>() {
+            @Override
+        public CarrierIdentifier createFromParcel(Parcel parcel) {
+            return new CarrierIdentifier(parcel);
+        }
+
+            @Override
+        public CarrierIdentifier[] newArray(int i) {
+            return new CarrierIdentifier[i];
+        }
+    };
+
+    private String mMcc;
+    private String mMnc;
+    private String mSpn;
+    private String mImsi;
+    private String mGid1;
+    private String mGid2;
+
+    public CarrierIdentifier(String mcc, String mnc, String spn, String imsi, String gid1,
+            String gid2) {
+        mMcc = mcc;
+        mMnc = mnc;
+        mSpn = spn;
+        mImsi = imsi;
+        mGid1 = gid1;
+        mGid2 = gid2;
+    }
+
+    /** @hide */
+    public CarrierIdentifier(Parcel parcel) {
+        readFromParcel(parcel);
+    }
+
+    /** Get the mobile country code. */
+    public String getMcc() {
+        return mMcc;
+    }
+
+    /** Get the mobile network code. */
+    public String getMnc() {
+        return mMnc;
+    }
+
+    /** Get the service provider name. */
+    public String getSpn() {
+        return mSpn;
+    }
+
+    /** Get the international mobile subscriber identity. */
+    public String getImsi() {
+        return mImsi;
+    }
+
+    /** Get the group identifier level 1. */
+    public String getGid1() {
+        return mGid1;
+    }
+
+    /** Get the group identifier level 2. */
+    public String getGid2() {
+        return mGid2;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mMcc);
+        out.writeString(mMnc);
+        out.writeString(mSpn);
+        out.writeString(mImsi);
+        out.writeString(mGid1);
+        out.writeString(mGid2);
+    }
+
+    /** @hide */
+    public void readFromParcel(Parcel in) {
+        mMcc = in.readString();
+        mMnc = in.readString();
+        mSpn = in.readString();
+        mImsi = in.readString();
+        mGid1 = in.readString();
+        mGid2 = in.readString();
+    }
+}
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index 3d6ebca..ac15ae5 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -83,6 +83,11 @@
      */
     public static final int DOWNLOAD_STATUS_ERROR = 2;
 
+    /**
+     * Flag to request SMS delivery status report.
+     */
+    public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1;
+
     private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper();
 
     /**
@@ -106,12 +111,14 @@
 
     /**
      * Override this method to intercept text SMSs sent from the device.
+     * @deprecated Override {@link #onSendTextSms} below instead.
      *
      * @param text the text to send
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
      * @param callback result callback. Call with a {@link SendSmsResult}.
      */
+    @Deprecated
     public void onSendTextSms(
             @NonNull String text, int subId, @NonNull String destAddress,
             @NonNull ResultCallback<SendSmsResult> callback) {
@@ -123,20 +130,78 @@
     }
 
     /**
+     * Override this method to intercept text SMSs sent from the device.
+     *
+     * @param text the text to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
+     *        {@link #SEND_FLAG_REQUEST_DELIVERY_STATUS}.
+     * @param callback result callback. Call with a {@link SendSmsResult}.
+     */
+    public void onSendTextSms(
+            @NonNull String text, int subId, @NonNull String destAddress,
+            int sendSmsFlag, @NonNull ResultCallback<SendSmsResult> callback) {
+        // optional
+        onSendTextSms(text, subId, destAddress, callback);
+    }
+
+    /**
+     * Override this method to intercept binary SMSs sent from the device.
+     * @deprecated Override {@link #onSendDataSms} below instead.
+     *
+     * @param data the binary content
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort the destination port
+     * @param callback result callback. Call with a {@link SendSmsResult}.
+     */
+    @Deprecated
+    public void onSendDataSms(@NonNull byte[] data, int subId,
+            @NonNull String destAddress, int destPort,
+            @NonNull ResultCallback<SendSmsResult> callback) {
+        // optional
+        try {
+            callback.onReceiveResult(new SendSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 0));
+        } catch (RemoteException ex) {
+        }
+    }
+
+    /**
      * Override this method to intercept binary SMSs sent from the device.
      *
      * @param data the binary content
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
      * @param destPort the destination port
+     * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
+     *        {@link #SEND_FLAG_REQUEST_DELIVERY_STATUS}.
      * @param callback result callback. Call with a {@link SendSmsResult}.
      */
     public void onSendDataSms(@NonNull byte[] data, int subId,
-            @NonNull String destAddress, int destPort,
+            @NonNull String destAddress, int destPort, int sendSmsFlag,
             @NonNull ResultCallback<SendSmsResult> callback) {
         // optional
+        onSendDataSms(data, subId, destAddress, destPort, callback);
+    }
+
+    /**
+     * Override this method to intercept long SMSs sent from the device.
+     * @deprecated Override {@link #onSendMultipartTextSms} below instead.
+     *
+     * @param parts a {@link List} of the message parts
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param callback result callback. Call with a {@link SendMultipartSmsResult}.
+     */
+    @Deprecated
+    public void onSendMultipartTextSms(@NonNull List<String> parts,
+            int subId, @NonNull String destAddress,
+            @NonNull ResultCallback<SendMultipartSmsResult> callback) {
+        // optional
         try {
-            callback.onReceiveResult(new SendSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, 0));
+            callback.onReceiveResult(
+                    new SendMultipartSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null));
         } catch (RemoteException ex) {
         }
     }
@@ -147,17 +212,15 @@
      * @param parts a {@link List} of the message parts
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
+     *        {@link #SEND_FLAG_REQUEST_DELIVERY_STATUS}.
      * @param callback result callback. Call with a {@link SendMultipartSmsResult}.
      */
     public void onSendMultipartTextSms(@NonNull List<String> parts,
-            int subId, @NonNull String destAddress,
+            int subId, @NonNull String destAddress, int sendSmsFlag,
             @NonNull ResultCallback<SendMultipartSmsResult> callback) {
         // optional
-        try {
-            callback.onReceiveResult(
-                    new SendMultipartSmsResult(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null));
-        } catch (RemoteException ex) {
-        }
+        onSendMultipartTextSms(parts, subId, destAddress, callback);
     }
 
     /**
@@ -358,8 +421,9 @@
 
         @Override
         public void sendTextSms(String text, int subId, String destAddress,
-                                final ICarrierMessagingCallback callback) {
-            onSendTextSms(text, subId, destAddress, new ResultCallback<SendSmsResult>() {
+                int sendSmsFlag, final ICarrierMessagingCallback callback) {
+            onSendTextSms(text, subId, destAddress, sendSmsFlag,
+                    new ResultCallback<SendSmsResult>() {
                     @Override
                     public void onReceiveResult(final SendSmsResult result) throws RemoteException {
                         callback.onSendSmsComplete(result.getSendStatus(), result.getMessageRef());
@@ -369,8 +433,9 @@
 
         @Override
         public void sendDataSms(byte[] data, int subId, String destAddress, int destPort,
-                                final ICarrierMessagingCallback callback) {
-            onSendDataSms(data, subId, destAddress, destPort, new ResultCallback<SendSmsResult>() {
+                int sendSmsFlag, final ICarrierMessagingCallback callback) {
+            onSendDataSms(data, subId, destAddress, destPort, sendSmsFlag,
+                    new ResultCallback<SendSmsResult>() {
                     @Override
                     public void onReceiveResult(final SendSmsResult result) throws RemoteException {
                         callback.onSendSmsComplete(result.getSendStatus(), result.getMessageRef());
@@ -380,8 +445,8 @@
 
         @Override
         public void sendMultipartTextSms(List<String> parts, int subId, String destAddress,
-                                         final ICarrierMessagingCallback callback) {
-                onSendMultipartTextSms(parts, subId, destAddress,
+                int sendSmsFlag, final ICarrierMessagingCallback callback) {
+            onSendMultipartTextSms(parts, subId, destAddress, sendSmsFlag,
                         new ResultCallback<SendMultipartSmsResult>() {
                                 @Override
                                 public void onReceiveResult(final SendMultipartSmsResult result)
diff --git a/core/java/android/service/carrier/ICarrierConfigService.aidl b/core/java/android/service/carrier/ICarrierConfigService.aidl
new file mode 100644
index 0000000..d8390b6
--- /dev/null
+++ b/core/java/android/service/carrier/ICarrierConfigService.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015, 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.service.carrier;
+
+import android.os.Bundle;
+import android.service.carrier.CarrierIdentifier;
+
+/**
+ * Service used to get carrier config from carrier apps.
+ *
+ * @see android.service.carrier.CarrierConfigService
+ * @hide
+ */
+interface ICarrierConfigService {
+
+    /** @see android.service.carrier.CarrierConfigService#onLoadConfig */
+    Bundle getCarrierConfig(in CarrierIdentifier id);
+}
\ No newline at end of file
diff --git a/core/java/android/service/carrier/ICarrierMessagingService.aidl b/core/java/android/service/carrier/ICarrierMessagingService.aidl
index 40a9047..2d96c3d 100644
--- a/core/java/android/service/carrier/ICarrierMessagingService.aidl
+++ b/core/java/android/service/carrier/ICarrierMessagingService.aidl
@@ -48,9 +48,10 @@
      * @param text the text to send
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
      * @param callback the callback to notify upon completion
      */
-    void sendTextSms(String text, int subId, String destAddress,
+    void sendTextSms(String text, int subId, String destAddress, int sendSmsFlag,
             in ICarrierMessagingCallback callback);
 
     /**
@@ -62,10 +63,11 @@
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
      * @param destPort port number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
      * @param callback the callback to notify upon completion
      */
     void sendDataSms(in byte[] data, int subId, String destAddress, int destPort,
-            in ICarrierMessagingCallback callback);
+            int sendSmsFlag, in ICarrierMessagingCallback callback);
 
     /**
      * Request sending a new multi-part text SMS from the device.
@@ -75,10 +77,11 @@
      * @param parts the parts of the multi-part text SMS to send
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
      * @param callback the callback to notify upon completion
      */
     void sendMultipartTextSms(in List<String> parts, int subId, String destAddress,
-            in ICarrierMessagingCallback callback);
+            int sendSmsFlag, in ICarrierMessagingCallback callback);
 
     /**
      * Request sending a new MMS PDU from the device.
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index e97d61e..52da137 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -268,7 +268,7 @@
     return (jboolean) !setNetworkForProcess(netId);
 }
 
-static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz)
+static jint android_net_utils_getBoundNetworkForProcess(JNIEnv *env, jobject thiz)
 {
     return getNetworkForProcess();
 }
@@ -306,7 +306,7 @@
     { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
     { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
-    { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess },
+    { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
     { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
     { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ccdb5db..6c1c352 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -208,7 +208,9 @@
     <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTABLE" />
     <protected-broadcast android:name="android.intent.action.MEDIA_EJECT" />
 
+    <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL" />
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+    <!-- @deprecated.  Only {@link android.net.ConnectivityManager.CONNECTIVITY_ACTION} is sent. -->
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
     <protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
     <protected-broadcast android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
@@ -2923,6 +2925,15 @@
         android:description="@string/permdesc_bindCarrierMessagingService"
         android:protectionLevel="signature|system" />
 
+    <!-- The system process that pulls carrier configuration from carrier apps will
+         have this permission. Carrier apps that provide
+         {@link android.service.carrier.CarrierConfigService} should require this
+         permission for clients binding to their service. -->
+    <permission android:name="android.permission.BIND_CARRIER_CONFIG_SERVICE"
+        android:label="@string/permlab_bindCarrierConfigService"
+        android:description="@string/permdesc_bindCarrierConfigService"
+        android:protectionLevel="signature|system" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f1da2f9..c22a1cb 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -437,6 +437,9 @@
          point on the move. A value of 0 means no periodic scans will be used in the framework. -->
     <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
 
+    <!-- Integer indicating disconnect mode scan interval in milliseconds -->
+    <integer translatable="false" name="config_wifi_disconnected_scan_interval">15000</integer>
+
     <!-- Integer indicating associated partial scan interval in milliseconds -->
     <integer translatable="false" name="config_wifi_framework_associated_scan_interval">20000</integer>
 
@@ -486,6 +489,9 @@
     <!-- Wifi driver supports batched scan -->
     <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
 
+    <!-- Wifi HAL supported PNO -->
+    <bool translatable="false" name="config_wifi_hal_pno_enable">false</bool>
+
     <!-- Idle Receive current for wifi radio. 0 by default-->
     <integer translatable="false" name="config_wifi_idle_receive_cur_ma">1</integer>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 23ed5ad..072d633 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -255,6 +255,8 @@
     <string-array name="wfcOperatorErrorNotificationMessages" />
     <!-- Template for showing cellular network operator name while WFC is active -->
     <string name="wfcSpnFormat">%s</string>
+    <!-- Template for showing operator name for data connection while WFC is active -->
+    <string name="wfcDataSpnFormat">%s</string>
     <!-- WFC, summary for Disabled -->
     <string name="wifi_calling_off_summary">Off</string>
     <!-- WFC, summary for Wi-Fi Preferred -->
@@ -2395,6 +2397,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindCarrierMessagingService">Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindCarrierConfigService">bind to a carrier config service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindCarrierConfigService">Allows the holder to bind to a carrier config service. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4bf7735..d33f667 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -371,7 +371,9 @@
   <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_disconnected_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
+  <java-symbol type="bool" name="config_wifi_hal_pno_enable" />
   <java-symbol type="integer" name="db_connection_pool_size" />
   <java-symbol type="integer" name="db_journal_size_limit" />
   <java-symbol type="integer" name="db_wal_autocheckpoint" />
@@ -758,6 +760,7 @@
   <java-symbol type="array" name="wfcOperatorErrorAlertMessages" />
   <java-symbol type="array" name="wfcOperatorErrorNotificationMessages" />
   <java-symbol type="string" name="wfcSpnFormat" />
+  <java-symbol type="string" name="wfcDataSpnFormat" />
   <java-symbol type="string" name="wifi_calling_off_summary" />
   <java-symbol type="string" name="wfc_mode_wifi_preferred_summary" />
   <java-symbol type="string" name="wfc_mode_cellular_preferred_summary" />
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index 6ae7c1a..d0f8c71 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -33,7 +33,10 @@
 </div>
 </div>
 
-<p>Android Cloud to Device Messaging (C2DM) is deprecated. The C2DM service will continue to be maintained in the short term, but C2DM will accept no new users, and it will grant no new quotas. <strong>C2DM developers are strongly encouraged to move to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+<p>Android Cloud to Device Messaging (C2DM) was officially deprecated on June 26, 2012, and has been
+ shut down completely as of April 1, 2015.  <strong>C2DM developers are strongly encouraged to move
+  to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+
 <p>This document is addressed to  C2DM developers who are moving to GCM. It describes the differences between GCM and C2DM, and explains how to migrate existing C2DM apps to GCM.</p>
 
 
diff --git a/docs/html/guide/index.jd b/docs/html/guide/index.jd
index d78a1b1..cb4f65c 100644
--- a/docs/html/guide/index.jd
+++ b/docs/html/guide/index.jd
@@ -30,7 +30,7 @@
 work in the background.</p>
 
 <p>From one component you can start another component using an <em>intent</em>. You can even start
-a component in a different app, such an activity in a maps app to show an address. This model
+a component in a different app, such as an activity in a maps app to show an address. This model
 provides multiple entry points for a single app and allows any app to behave as a user's "default"
 for an action that other apps may invoke.</p>
 
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index c1256f9..99e64d9 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -13,10 +13,11 @@
           android:<a href="#clear">clearTaskOnLaunch</a>=["true" | "false"]
           android:<a href="#config">configChanges</a>=["mcc", "mnc", "locale",
                                  "touchscreen", "keyboard", "keyboardHidden",
-                                 "navigation", "screenLayout", "fontScale", "uiMode",
-                                 "orientation", "screenSize", "smallestScreenSize"]
-          android:<a href="#dlmode">documentLaunchMode</a>=["intoExisting", "always",
-                                  "none", "never"]
+                                 "navigation", "screenLayout", "fontScale",
+                                 "uiMode", "orientation", "screenSize",
+                                 "smallestScreenSize"]
+          android:<a href="#dlmode">documentLaunchMode</a>=["intoExisting" | "always" |
+                                  "none" | "never"]
           android:<a href="#enabled">enabled</a>=["true" | "false"]
           android:<a href="#exclude">excludeFromRecents</a>=["true" | "false"]
           android:<a href="#exported">exported</a>=["true" | "false"]
diff --git a/docs/html/images/tv/channel-info.png b/docs/html/images/tv/channel-info.png
new file mode 100644
index 0000000..5a48078
--- /dev/null
+++ b/docs/html/images/tv/channel-info.png
Binary files differ
diff --git a/docs/html/images/tv/do-not-attempt.png b/docs/html/images/tv/do-not-attempt.png
new file mode 100644
index 0000000..18a8775
--- /dev/null
+++ b/docs/html/images/tv/do-not-attempt.png
Binary files differ
diff --git a/docs/html/images/tv/prog-guide.png b/docs/html/images/tv/prog-guide.png
new file mode 100644
index 0000000..caa2278
--- /dev/null
+++ b/docs/html/images/tv/prog-guide.png
Binary files differ
diff --git a/docs/html/images/tv/tvinput-life.png b/docs/html/images/tv/tvinput-life.png
new file mode 100644
index 0000000..fc53f89
--- /dev/null
+++ b/docs/html/images/tv/tvinput-life.png
Binary files differ
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index b08fbcf..e8706c1 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -78,6 +78,19 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 22.0.1</a> <em>(March 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Fixed compatibility issues with
+    <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> kernels on
+    Android 4.4 (API level 19) to Android 4.1 (API level 16) devices.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 22.0.0</a> <em>(March 2015)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/docs/html/tools/testing-support-library/index.jd b/docs/html/tools/testing-support-library/index.jd
index aeace8e..c8c9ef5 100644
--- a/docs/html/tools/testing-support-library/index.jd
+++ b/docs/html/tools/testing-support-library/index.jd
@@ -391,7 +391,9 @@
 
   <p>
     To learn more about using Espresso, see the
-    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a>.
+    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a> and
+    <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">
+      Testing UI for a Single App</a> training.
   </p>
 
   <h3 id="UIAutomator">
@@ -531,7 +533,9 @@
 
   <p>
     To learn more about using UI Automator, see the
-    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a>.
+    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a> and
+    <a href="{@docRoot}training/testing/ui-testing/uiautomator-testing.html">
+      Testing UI for Multiple Apps</a> training.
   </p>
 
   <h2 id="setup">
diff --git a/docs/html/training/auto/start/index.jd b/docs/html/training/auto/start/index.jd
index 54500ac..22e7521 100644
--- a/docs/html/training/auto/start/index.jd
+++ b/docs/html/training/auto/start/index.jd
@@ -55,14 +55,6 @@
 setting up your development environment and meeting the the minimum requirements
 to enable an app to communicate with Auto.</p>
 
-<p class="note"><strong>Important:</strong> If you are planning to develop
-apps for Auto, you are encouraged to begin enabling and testing your
-apps now. However, Auto-enabled apps cannot be published at this time.
-Join the
-<a href="http://g.co/AndroidAutoDev" class="external-link">Auto
-Developers Google+ community</a> for updates on when you will be able to submit
-your Auto-enabled apps.</p>
-
 <h2 id="dev-project">Set Up an Auto Project</h2>
 <p>This section describes how to create a new app or modify an existing app to
 communicate with Auto.</p>
diff --git a/docs/html/training/custom-views/optimizing-view.jd b/docs/html/training/custom-views/optimizing-view.jd
index 7f2e762..022618b 100644
--- a/docs/html/training/custom-views/optimizing-view.jd
+++ b/docs/html/training/custom-views/optimizing-view.jd
@@ -12,33 +12,21 @@
     <div id="tb">
 
         <h2>This lesson teaches you to</h2>
-        <ol>
-            <li><a href="#less">Do Less, Less Frequently</a></li>
-            <li><a href="#accelerate">Use Hardware Acceleration</a></li>
-        </ol>
-
-        <h2>You should also read</h2>
         <ul>
-            <li><a href="{@docRoot}guide/topics/graphics/hardware-accel.html">
-                Hardware Acceleration
-            </a>
-        </li>
-    </ul>
-<h2>Try it out</h2>
-<div class="download-box">
-<a href="{@docRoot}shareables/training/CustomView.zip"
-class="button">Download the sample</a>
-<p class="filename">CustomView.zip</p>
-</div>
-</div>
+            <li><a href="#less">Do Less, Less Frequently</a></li>
+        </ul>
+        <h2>Try it out</h2>
+        <div class="download-box">
+            <a href="{@docRoot}shareables/training/CustomView.zip"
+                class="button">Download the sample</a>
+            <p class="filename">CustomView.zip</p>
         </div>
-
+    </div>
+</div>
 
 <p>Now that you have a well-designed view that responds to gestures and transitions between states,
-you need to ensure
-that the view runs fast. To avoid a UI that feels sluggish or stutters during playback, you must
-ensure that your
-animations consistently run at 60 frames per second.</p>
+ensure that the view runs fast. To avoid a UI that feels sluggish or stutters during playback,
+ensure that animations consistently run at 60 frames per second.</p>
 
 <h2 id="less">Do Less, Less Frequently</h2>
 
@@ -52,19 +40,13 @@
 allocation while an
 animation is running.</p>
 
-<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, you should also make sure
+<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, also make sure
 it's called as
 infrequently as possible. Most calls to {@link android.view.View#onDraw onDraw()} are the result of
 a call to {@link
 android.view.View#invalidate() invalidate()}, so eliminate unnecessary calls to {@link
 android.view.View#invalidate()
-invalidate()}. When possible, call the four-parameter variant of {@link
-android.view.View#invalidate() invalidate()}
-rather than the version that takes no parameters. The no-parameter variant invalidates the entire
-view, while the
-four-parameter variant invalidates only a specified portion of the view. This approach allows draw calls to
-be more efficient and
-can eliminate unnecessary invalidation of views that fall outside the invalid rectangle.</p>
+invalidate()}.</p>
 
 <p>Another very expensive operation is traversing layouts. Any time a view calls {@link
 android.view.View#requestLayout()
@@ -78,7 +60,7 @@
 as shallow as
 possible.</p>
 
-<p>If you have a complex UI, you should consider writing a custom {@link android.view.ViewGroup
+<p>If you have a complex UI, consider writing a custom {@link android.view.ViewGroup
 ViewGroup} to perform
 its layout. Unlike the built-in views, your custom view can make application-specific assumptions
 about the size and
@@ -88,89 +70,3 @@
 views, but it never
 measures them. Instead, it sets their sizes directly according to its own custom layout
 algorithm.</p>
-
-<h2 id="accelerate">Use Hardware Acceleration</h2>
-
-<p>As of Android 3.0, the Android 2D graphics system can be accelerated by the GPU (Graphics
-Processing Unit) hardware
-found in most newer Android devices. GPU hardware acceleration can result in a tremendous
-performance increase for many
-applications, but it isn't the right choice for every application. The Android framework
-gives you the ability to finely control which parts of your application are or are not
-hardware accelerated.</p>
-
-<p>See <a href="{@docRoot}guide/topics/graphics/hardware-accel.html">Hardware Acceleration</a>
-        in the Android Developers Guide for directions on how to enable acceleration at the
-        application, activity, or window level. Notice  that in addition to the directions in
-        the developer guide, you must also set your application's target API to 11 or higher by
-        specifying {@code &lt;uses-sdk
-        android:targetSdkVersion="11"/&gt;} in your {@code AndroidManifest.xml} file.</p>
-
-<p>Once you've enabled hardware acceleration, you may or may not see a performance increase.
-Mobile GPUs are very good at certain tasks, such as scaling, rotating, and translating
-bitmapped images. They are not particularly good at other tasks, such as drawing lines or curves. To
-get the most out of GPU acceleration, you should maximize the number of operations that the GPU is
-good at, and minimize the number of operations that the GPU isn't good at.</p>
-
-<p>In the PieChart example, for instance, drawing the pie is relatively expensive. Redrawing the pie
-each time it's
-rotated causes the UI to feel sluggish. The solution is to place the pie chart into a child
-{@link android.view.View} and set that
-{@link android.view.View}'s
-<a href="{@docRoot}reference/android/view/View.html#setLayerType(int, android.graphics.Paint)">
-    layer type</a> to {@link android.view.View#LAYER_TYPE_HARDWARE}, so that the GPU can cache it as
-a static
-image. The sample
-defines the child view as an inner class of {@code PieChart}, which minimizes the amount of code
-changes that are needed
-to implement this solution.</p>
-
-<pre>
-   private class PieView extends View {
-
-       public PieView(Context context) {
-           super(context);
-           if (!isInEditMode()) {
-               setLayerType(View.LAYER_TYPE_HARDWARE, null);
-           }
-       }
-       
-       &#64;Override
-       protected void onDraw(Canvas canvas) {
-           super.onDraw(canvas);
-
-           for (Item it : mData) {
-               mPiePaint.setShader(it.mShader);
-               canvas.drawArc(mBounds,
-                       360 - it.mEndAngle,
-                       it.mEndAngle - it.mStartAngle,
-                       true, mPiePaint);
-           }
-       }
-
-       &#64;Override
-       protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-           mBounds = new RectF(0, 0, w, h);
-       }
-
-       RectF mBounds;
-   }
-</pre>
-
-<p>After this code change, {@code PieChart.PieView.onDraw()} is called only when the view is first
-shown. During the rest
-of the application's lifetime, the pie chart is cached as an image, and redrawn at different
-rotation angles by the GPU.
-GPU hardware is particularly good at this sort of thing, and the performance difference is
-immediately noticeable.</p>
-
-<p>There is a tradeoff, though. Caching images as hardware layers consumes video memory, which is a
-limited resource.
-For this reason, the final version of {@code PieChart.PieView} only sets its layer type to
-{@link android.view.View#LAYER_TYPE_HARDWARE}
-while the user is actively scrolling. At all other times, it sets its layer type to
-{@link android.view.View#LAYER_TYPE_NONE}, which
-allows the GPU to stop caching the image.</p>
-
-<p>Finally, don't forget to profile your code. Techniques that improve performance on one view
-might negatively affect performance on another.</p>
diff --git a/docs/html/training/testing/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd
new file mode 100644
index 0000000..85f4ba4
--- /dev/null
+++ b/docs/html/training/testing/ui-testing/espresso-testing.jd
@@ -0,0 +1,579 @@
+page.title=Testing UI for a Single App
+page.tags=testing,espresso
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+
+        <ul>
+          <li>Android 2.2 (API level 8) or higher
+          </li>
+
+          <li>
+            <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support
+            Library</a>
+          </li>
+        </ul>
+
+        <h2>
+          This lesson teaches you to
+        </h2>
+
+        <ol>
+          <li>
+            <a href="#setup">Set Up Espresso</a>
+          </li>
+
+          <li>
+            <a href="#build">Create an Espresso Test Class</a>
+          </li>
+
+          <li>
+            <a href="#run">Run Espresso Tests on a Device or Emulator</a>
+          </li>
+        </ol>
+
+        <h2>
+          You should also read
+        </h2>
+
+        <ul>
+           <li><a href="{@docRoot}reference/android/support/test/package-summary.html">
+              Espresso API Reference</a></li>
+        </ul>
+
+        <h2>
+          Try it out
+        </h2>
+
+        <ul>
+          <li>
+            <a href="https://github.com/googlesamples/android-testing"
+            class="external-link">Espresso Code Samples</a>
+          </li>
+        </ul>
+      </div>
+    </div>
+
+    <p>
+      Testing user interactions
+      within a single app helps to ensure that users do not
+      encounter unexpected results or have a poor experience when interacting with your app.
+      You should get into the habit of creating user interface (UI) tests if you need to verify
+      that the UI of your app is functioning correctly.
+    </p>
+
+    <p>
+      The Espresso testing framework, provided by the
+      <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>,
+      provides APIs for writing UI tests to simulate user interactions within a
+      single target app. Espresso tests can run on devices running Android 2.2 (API level 8) and
+      higher. A key benefit of using Espresso is that it provides automatic synchronization of test
+      actions with the UI of the app you are testing. Espresso detects when the main thread is idle,
+      so it is able to run your test commands at the appropriate time, improving the reliability of
+      your tests. This capability also relieves you from having to adding any timing workarounds,
+      such as a sleep period, in your test code.
+    </p>
+
+    <p>
+      The Espresso testing framework is an instrumentation-based API and works
+      with the
+      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
+      AndroidJUnitRunner}</a> test runner.
+    </p>
+
+    <h2 id="setup">
+      Set Up Espresso
+    </h2>
+
+    <p>
+      Before you begin using Espresso, you must:
+    </p>
+
+    <ul>
+      <li>
+        <strong>Install the Android Testing Support Library</strong>. The Espresso API is
+        located under the {@code com.android.support.test.espresso} package. These classes allow
+        you to create tests that use the Espresso testing framework. To learn how to install the
+        library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
+        Testing Support Library Setup</a>.
+      </li>
+
+      <li>
+        <strong>Set up your project structure.</strong> In your Gradle project, the source code for
+        the target app that you want to test is typically placed under the {@code app/src/main}
+        folder. The source code for instrumentation tests, including
+        your Espresso tests, must be placed under the <code>app/src/androidTest</code> folder. To
+        learn more about setting up your project directory, see
+        <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
+      </li>
+
+      <li>
+        <strong>Specify your Android testing dependencies</strong>. In order for the
+        <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
+        correctly build and run your Espresso tests, you must specify the following libraries in
+        the {@code build.gradle} file of your Android app module:
+
+        <pre>
+dependencies {
+    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
+}
+</pre>
+      </li>
+
+      <li>
+        <strong>Turn off animations on your test device.</strong> Leaving system animations turned
+        on in the test device might cause unexpected results or may lead your test to fail. Turn
+        off animations from <em>Settings</em> by opening <em>Developing Options</em> and
+        turning all the following options off:
+        <ul>
+          <li>
+            <em>Window animation scale</em>
+          </li>
+
+          <li>
+            <em>Transition animation scale</em>
+          </li>
+
+          <li>
+            <em>Animator duration scale</em>
+          </li>
+        </ul>
+      </li>
+    </ul>
+
+    <h2 id="build">
+      Create an Espresso Test Class
+    </h2>
+
+    <p>
+      To create an Espresso test, create a Java class or an
+      {@link android.test.ActivityInstrumentationTestCase2}
+      subclass that follows this programming model:
+    </p>
+
+    <ol>
+      <li>Find the UI component you want to test in an {@link android.app.Activity} (for example, a
+      sign-in button in the app) by calling the
+      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+        {@code onView()}</a> method, or the
+      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
+      {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
+      </li>
+
+      <li>Simulate a specific user interaction to perform on that UI component, by calling the
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
+      or
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
+      method and passing in the user action (for example, click on the sign-in button). To sequence
+      multiple actions on the same UI component, chain them using a comma-separated list in your
+      method argument.
+      </li>
+
+      <li>Repeat the steps above as necessary, to simulate a user flow across multiple
+      activities in the target app.
+      </li>
+
+      <li>Use the
+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
+        methods to check that the UI reflects the expected
+      state or behavior, after these user interactions are performed.
+      </li>
+    </ol>
+
+    <p>
+      These steps are covered in more detail in the sections below.
+    </p>
+
+    <p>
+      The following code snippet shows how your test class might invoke this basic workflow:
+    </p>
+
+<pre>
+onView(withId(R.id.my_view))            // withId(R.id.my_view) is a ViewMatcher
+        .perform(click())               // click() is a ViewAction
+        .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
+</pre>
+
+    <h3 id="espresso-aitc2">
+      Using Espresso with ActivityInstrumentationTestCase2
+    </h3>
+
+    <p>
+      If you are subclassing {@link android.test.ActivityInstrumentationTestCase2}
+      to create your Espresso test class, you must inject an
+      {@link android.app.Instrumentation} instance into your test class. This step is required in
+      order for your Espresso test to run with the
+      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+      test runner.
+    </p>
+
+    <p>
+      To do this, call the
+      {@link android.test.InstrumentationTestCase#injectInstrumentation(android.app.Instrumentation) injectInstrumentation()}
+      method and pass in the result of
+      <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()">
+      {@code InstrumentationRegistry.getInstrumentation()}</a>, as shown in the following code
+      example:
+    </p>
+
+<pre>
+import android.support.test.InstrumentationRegistry;
+
+public class MyEspressoTest
+        extends ActivityInstrumentationTestCase2&lt;MyActivity&gt; {
+
+    private MyActivity mActivity;
+
+    public MyEspressoTest() {
+        super(MyActivity.class);
+    }
+
+    &#64;Before
+    public void setUp() throws Exception {
+        super.setUp();
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+        mActivity = getActivity();
+    }
+
+   ...
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Previously, {@link android.test.InstrumentationTestRunner}
+would inject the {@link android.app.Instrumentation} instance, but this test runner is being
+deprecated.</p>
+
+    <h3 id="accessing-ui-components">
+      Accessing UI Components
+    </h3>
+
+    <p>
+      Before Espresso can interact with the app under test, you must first specify the UI component
+      or <em>view</em>. Espresso supports the use of
+<a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
+      for specifying views and adapters in your app.
+    </p>
+
+    <p>
+      To find the view, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a>
+      method and pass in a view matcher that specifies the view that you are targeting. This is
+      described in more detail in <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
+      The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a> method returns a
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">
+      {@code ViewInteraction}</a>
+      object that allows your test to interact with the view.
+      However, calling  the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a> method may not work if you want to locate a view in
+      an {@link android.widget.AdapterView} layout. In this case, follow the instructions in
+      <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a> instead.
+    </p>
+
+    <p class="note">
+      <strong>Note</strong>: The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a> method does not check if the view you specified is
+      valid. Instead, Espresso searches only the current view hierarchy, using the matcher provided.
+      If no match is found, the method throws a
+      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
+      {@code NoMatchingViewException}</a>.
+    </p>
+
+    <p>
+      The following code snippet shows how you might write a test that accesses an
+      {@link android.widget.EditText} field, enters a string of text, closes the virtual keyboard,
+      and then performs a button click.
+    </p>
+
+<pre>
+public void testChangeText_sameActivity() {
+    // Type text and then press the button.
+    onView(withId(R.id.editTextUserInput))
+            .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard());
+    onView(withId(R.id.changeTextButton)).perform(click());
+
+    // Check that the text was changed.
+    ...
+}
+</pre>
+
+    <h4 id="specifying-view-matcher">
+      Specifying a View Matcher
+    </h4>
+
+    <p>
+      You can specify a view matcher by using these approaches:
+    </p>
+
+    <ul>
+      <li>Calling methods in the
+        <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">
+        {@code ViewMatchers}</a> class. For example, to find a view by looking for a text string it
+        displays, you can call a method like this:
+        <pre>
+onView(withText("Sign-in"));
+</pre>
+
+<p>Similarly you can call
+<a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">
+{@code withId()}</a> and providing the resource ID ({@code R.id}) of the view, as shown in the
+following example:</p>
+
+<pre>
+onView(withId(R.id.button_signin));
+</pre>
+
+    <p>
+      Android resource IDs are not guaranteed to be unique. If your test attempts to match to a
+      resource ID used by more than one view, Espresso throws an
+<a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">
+  {@code AmbiguousViewMatcherException}</a>.
+    </p>
+      </li>
+      <li>Using the Hamcrest
+      <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
+         class="external-link">{@code Matchers}</a> class. You can use the
+      {@code allOf()} methods to combine multiple matchers, such as
+      {@code containsString()} and {@code instanceOf()}. This approach allows you to
+      filter the match results more narrowly, as shown in the following example:
+<pre>
+onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
+</pre>
+<p>You can use the {@code not} keyword to filter for views that don't correspond to the matcher, as
+shown in the following example:</p>
+<pre>
+onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
+</pre>
+<p>To use these methods in your test, import the {@code org.hamcrest.Matchers} package. To
+learn more about Hamcrest matching, see the
+<a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
+</p>
+      </li>
+    </ul>
+
+    <p>
+      To improve the performance of your Espresso tests, specify the minimum matching information
+      needed to find your target view. For example, if a view is uniquely identifiable by its
+      descriptive text, you do not need to specify that it is also assignable from the
+      {@link android.widget.TextView} instance.
+    </p>
+
+    <h4 id="#locating-adpeterview-view">
+      Locating a view in an AdapterView
+    </h4>
+
+    <p>
+      In an {@link android.widget.AdapterView} widget, the view is dynamically populated with child
+      views at runtime. If the target view you want to test is inside an
+      {@link android.widget.AdapterView}
+      (such as a {@link android.widget.ListView}, {@link android.widget.GridView}, or
+      {@link android.widget.Spinner}), the
+<a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+  {@code onView()}</a> method might not work because only a
+      subset of the views may be loaded in the current view hierarchy.
+    </p>
+
+    <p>
+      Instead, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+      method to obtain a
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">
+      {@code DataInteraction}</a>
+      object to access the target view element. Espresso handles loading the target view element
+      into the current view hierarchy. Espresso also takes care of scrolling to the target element,
+      and putting the element into focus.
+    </p>
+
+    <p class="note">
+      <strong>Note</strong>: The
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+      method does not check if if the item you specified corresponds with a view. Espresso searches
+      only the current view hierarchy. If no match is found, the method throws a
+      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
+        {@code NoMatchingViewException}</a>.
+    </p>
+
+    <p>
+      The following code snippet shows how you can use the
+      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+      method together
+      with Hamcrest matching to search for a specific row in a list that contains a given string.
+      In this example, the {@code LongListActivity} class contains a list of strings exposed
+      through a {@link android.widget.SimpleAdapter}.
+    </p>
+
+<pre>
+onData(allOf(is(instanceOf(Map.class)),
+        hasEntry(equalTo(LongListActivity.ROW_TEXT), is(str))));
+</pre>
+
+    <h3 id="perform-actions">
+      Performing Actions
+    </h3>
+
+    <p>
+      Call the <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
+      or
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
+      methods to
+      simulate user interactions on the UI component. You must pass in one or more
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
+      objects as arguments. Espresso fires each action in sequence according to
+      the given order, and executes them in the main thread.
+    </p>
+
+    <p>
+      The
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
+      class provides a list of helper methods for specifying common actions.
+      You can use these methods as convenient shortcuts instead of creating and configuring
+      individual <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
+      objects. You can specify such actions as:
+    </p>
+
+    <ul>
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
+       Clicks on the view.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
+       Clicks on a view and enters a specified string.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
+       Scrolls to the view. The
+        target view must be subclassed from {@link android.widget.ScrollView}
+        and the value of its
+        <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
+        property must be {@link android.view.View#VISIBLE}. For views that extend
+        {@link android.widget.AdapterView} (for example,
+        {@link android.widget.ListView}),
+        the
+        <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+        method takes care of scrolling for you.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
+       Performs a key press using a specified keycode.
+      </li>
+
+      <li>
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
+      Clears the text in the target view.
+      </li>
+    </ul>
+
+    <p>
+      If the target view is inside a {@link android.widget.ScrollView}, perform the
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
+      action first to display the view in the screen before other proceeding
+      with other actions. The
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
+      action will have no effect if the view is already displayed.
+    </p>
+
+    <h3 id="verify-results">
+      Verifying Results
+    </h3>
+
+    <p>
+      Call the
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
+      or
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
+      method to assert
+      that the view in the UI matches some expected state. You must pass in a
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">
+      {@code ViewAssertion}</a> object as the argument. If the assertion fails, Espresso throws
+      an {@link junit.framework.AssertionFailedError}.
+    </p>
+
+    <p>
+      The
+  <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
+      class provides a list of helper methods for specifying common
+      assertions. The assertions you can use include:
+    </p>
+
+    <ul>
+      <li>
+        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
+Asserts that there is no view matching the specified criteria in the current view hierarchy.
+      </li>
+
+      <li>
+        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
+        Asserts that the specified view exists in the current view hierarchy
+        and its state matches some given Hamcrest matcher.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>
+       : Asserts that the specified children views for a
+        parent view exist, and their state matches some given Hamcrest matcher.
+      </li>
+    </ul>
+
+    <p>
+      The following code snippet shows how you might check that the text displayed in the UI has
+      the same value as the text previously entered in the
+      {@link android.widget.EditText} field.
+    </p>
+<pre>
+public void testChangeText_sameActivity() {
+    // Type text and then press the button.
+    ...
+
+    // Check that the text was changed.
+    onView(withId(R.id.textToBeChanged))
+            .check(matches(withText(STRING_TO_BE_TYPED)));
+}
+</pre>
+
+<h2 id="run">Run Espresso Tests on a Device or Emulator</h2>
+
+    <p>
+      To run Espresso tests, you must use the
+      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+      class provided in the
+      <a href="{@docRoot}tools/testing-support-library/index.html">
+      Android Testing Support Library</a> as your default test runner. The
+      <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for
+      Gradle</a> provides a default directory ({@code src/androidTest/java}) for you to store the
+      instrumented test classes and test suites that you want to run on a device. The
+      plug-in compiles the test code in that directory and then executes the test app using
+      the configured test runner class.
+    </p>
+
+    <p>
+      To run Espresso tests in your Gradle project:
+    </p>
+
+    <ol>
+      <li>Specify
+        <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+        as the default test instrumentation runner in
+      your {@code build.gradle} file:
+
+  <pre>
+android {
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+}</pre>
+      </li>
+      <li>Run your tests from the command-line by calling the the {@code connectedCheck}
+        (or {@code cC}) task:
+  <pre>
+./gradlew cC</pre>
+      </li>
+    </ol>
\ No newline at end of file
diff --git a/docs/html/training/testing/ui-testing/index.jd b/docs/html/training/testing/ui-testing/index.jd
new file mode 100644
index 0000000..20422f7
--- /dev/null
+++ b/docs/html/training/testing/ui-testing/index.jd
@@ -0,0 +1,76 @@
+page.title=Automating User Interface Tests
+page.tags=testing
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+        <h2>
+          You should also read
+        </h2>
+
+        <ul>
+          <li>
+            <a href="{@docRoot}tools/testing-support-library/index.html">Testing Support Library</a>
+          </li>
+        </ul>
+</div>
+</div>
+
+<p>User interface (UI) testing lets you ensure that your app meets its functional requirements
+and achieves a high standard of quality such that it is more likely to be successfully adopted by
+users.</p>
+
+<p>One approach to UI testing is to simply have a human tester perform a set of user operations on
+the target app and verify that it is behaving correctly. However, this manual approach can be
+time-consuming, tedious, and error-prone. A more efficient approach is to write your UI
+tests such that user actions are performed in an automated way. The automated approach allows
+you to run your tests quickly and reliably in a repeatable manner.</p>
+
+<p class="note"><strong>Note: </strong>It is strongly encouraged that you use
+<a href="{@docRoot}sdk/installing/studio.html">Android Studio</a> for
+building your test apps, because it provides project setup, library inclusion, and packaging
+conveniences. This class assumes you are using Android Studio.</p>
+
+<p>To automate UI tests with Android Studio, you implement your test code in a separate
+Android test folder ({@code src/androidTest/java}). The
+<a href="{@docRoot}tools/building/plugin-for-gradle.html">Android
+Plug-in for Gradle</a> builds a test app based on your test code, then loads the test app on the
+same device as the target app. In your test code, you can use UI testing frameworks to
+simulate user interactions on the target app, in order to perform testing tasks that cover specific
+usage scenarios.</p>
+
+<p>For testing Android apps, you typically create these types of automated UI tests:</p>
+
+<ul>
+<li><em>UI tests that span a single app:</em> This type of test verifies that the target app behaves
+as expected when a user performs a specific action or enters a specific input in its activities.
+It allows you to check that the target app returns the correct UI output in response
+to user interactions in the app’s activities. UI testing frameworks like Espresso allow you to
+programmatically simulate user actions and test complex intra-app user interactions.</li>
+<li><em>UI tests that span multiple apps:</em> This type of test verifies the correct behavior of
+interactions between different user apps or between user apps and system apps. For example, you
+might want to test that your camera app shares images correctly with a 3rd-party social media app,
+or with the default Android Photos app. UI testing frameworks that support cross-app interactions,
+such as UI Automator, allow you to create tests for such scenarios.</li>
+</ul>
+
+<p>The lessons in this class teach you how to use the tools and APIs in the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
+to build these types of automated tests. Before you begin building tests using these
+APIs, you must install the Android Testing Support Library, as described in
+<a href="{@docRoot}tools/testing-support-library/index.html#setup">Downloading the Android
+Testing Support Library</a>.</p>
+
+<h2>Lessons</h2>
+<dl>
+  <dt><strong><a href="espresso-testing.html">
+Testing UI for a Single App</a></strong></dt>
+    <dd>Learn how to test UI in a single app by using the Espresso testing framework.</dd>
+  <dt><strong><a href="uiautomator-testing.html">
+Testing UI for Multiple Apps</a></strong></dt>
+    <dd>Learn how to test UI in multiple apps by using the UI Automator testing framework</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/training/testing/ui-testing/uiautomator-testing.jd b/docs/html/training/testing/ui-testing/uiautomator-testing.jd
new file mode 100644
index 0000000..e314b70
--- /dev/null
+++ b/docs/html/training/testing/ui-testing/uiautomator-testing.jd
@@ -0,0 +1,520 @@
+page.title=Testing UI for Multiple Apps
+page.tags=testing,ui automator
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+
+  <ul>
+    <li>Android 4.3 (API level 18) or higher</li>
+    <li><a href="{@docRoot}tools/testing-support-library/index.html">
+      Android Testing Support Library</a></li>
+  </ul>
+
+  <h2>This lesson teaches you to</h2>
+
+  <ol>
+    <li><a href="#setup">Set Up UI Automator</a></li>
+    <li><a href="#build">Create a UI Automator Test Class</a></li>
+    <li><a href="#run">Run UI Automator Tests on a Device or Emulator</a></li>
+  </ol>
+
+  <h2>You should also read</h2>
+
+  <ul>
+    <li><a href="{@docRoot}reference/android/support/test/package-summary.html">
+UI Automator API Reference</a></li>
+  </ul>
+
+  <h2>Try it out</h2>
+
+  <ul>
+    <li><a href="https://github.com/googlesamples/android-testing"
+class="external-link">UI Automator Code Samples</a></li>
+  </ul>
+</div>
+</div>
+
+<p>A user interface (UI) test that involves user interactions across multiple apps lets you
+verify that your app behaves correctly when the user flow crosses into other apps or into the
+system UI. An example of such a user flow is a messaging app that lets the user enter a text
+message, launches the Android contact picker so that the users can select recipients to send the
+message to, and then returns control to the original app for the user to submit the message.</p>
+
+<p>This lesson covers how to write such UI tests using the
+UI Automator testing framework provided by the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+The UI Automator APIs let you interact with visible elements on a device, regardless of
+which {@link android.app.Activity} is in focus. Your test can look up a UI component by using
+convenient descriptors such as the text displayed in that component or its content description. UI
+Automator tests can run on devices running Android 4.3 (API level 18) or higher.</p>
+
+<p>The UI Automator testing framework is an instrumentation-based API and works
+with the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+  {@code AndroidJUnitRunner}</a>
+test runner.
+</p>
+
+<h2 id="setup">Set Up UI Automator</h2>
+<p>Before you begin using UI Automator, you must:</p>
+
+  <ul>
+      <li>
+        <strong>Install the Android Testing Support Library</strong>. The UI Automator API is
+        located under the {@code com.android.support.test.uiautomator} package. These classes allow
+        you to create tests that use the Espresso testing framework. To learn how to install the
+        library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
+        Testing Support Library Setup</a>.
+      </li>
+
+      <li>
+        <strong>Set up your project structure.</strong> In your Gradle project, the source code for
+        the target app that you want to test is typically placed under the {@code app/src/main}
+        folder. The source code for instrumentation tests, including
+        your UI Automator tests, must be placed under the <code>app/src/androidTest</code> folder.
+        To learn more about setting up your project directory, see
+        <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
+      </li>
+
+      <li>
+        <strong>Specify your Android testing dependencies</strong>. In order for the
+        <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
+        correctly build and run your UI Automator tests, you must specify the following libraries in
+        the {@code build.gradle} file of your Android app module:
+
+        <pre>
+dependencies {
+    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0'
+}
+</pre>
+      </li>
+  </ul>
+
+<p>To optimize your UI Automator testing, you should first inspect the target app’s UI components
+and ensure that they are accessible. These optimization tips are described in the next two
+sections.</p>
+
+<h3 id="inspecting-ui">Inspecting the UI on a device</h3>
+<p>Before designing your test, inspect the UI components that are visible on the device. To
+ensure that your UI Automator tests can access these components, check that these components
+have visible text labels,
+<a href="http://developer.android.com/reference/android/view/View.html#attr_android:contentDescription">
+{@code android:contentDescription}</a>
+values, or both.</p>
+
+<p>The {@code uiautomatorviewer} tool provides a convenient visual interface to inspect the layout
+hierarchy and view the properties of UI components that are visible on the foreground of the device.
+This information lets you create more fine-grained tests using UI Automator. For example, you can
+create a UI selector that matches a specific visible property. </p>
+
+<p>To launch the {@code uiautomatorviewer} tool:</p>
+
+<ol>
+  <li>Launch the target app on a physical device.</li>
+  <li>Connect the device to your development machine.</li>
+  <li>Open a terminal window and navigate to the {@code &lt;android-sdk&gt;/tools/} directory.</li>
+  <li>Run the tool with this command:
+<pre>$ uiautomatorviewer</pre>
+  </li>
+</ol>
+
+<p>To view the UI properties for your application:</p>
+
+<ol>
+  <li>In the {@code uiautomatorviewer} interface, click the <strong>Device Screenshot</strong>
+button.</li>
+  <li>Hover over the snapshot in the left-hand panel to see the UI components identified by the
+{@code uiautomatorviewertool}. The properties are listed in the lower right-hand panel and the
+layout hierarchy in the upper right-hand panel.</li>
+  <li>Optionally, click on the <strong>Toggle NAF Nodes</strong> button to see UI components that
+are non-accessible to UI Automator. Only limited information may be available for these
+components.</li>
+</ol>
+
+<p>To learn about the common types of UI components provided by Android, see
+<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>.</p>
+
+<h3>Ensuring your Activity is accessible</h3>
+<p>The UI Automator test framework depends on the accessibility features of the Android framework
+to look up individual UI elements. As a developer, you should implement these minimum
+optimizations in your {@link android.app.Activity} to support UI Automator:</p>
+
+<ul>
+<li>Use the
+<a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">
+  {@code android:contentDescription}</a>
+attribute to label the {@link android.widget.ImageButton}, {@link android.widget.ImageView},
+{@link android.widget.CheckBox} and other user interface controls.</li>
+<li>Provide an <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
+attribute instead of a content description for {@link android.widget.EditText} fields.</li>
+<li>Associate an <a href="http://developer.android.com/reference/android/widget/TextView.html#attr_android:hint">
+  {@code android:hint}</a>
+attribute with any graphical icons used by controls that provide feedback to the user
+(for example, status or state information).</li>
+<li>Use the {@code uiautomatorviewer} tool to ensure that the UI component is accessible to the
+testing framework. You can also test the application by turning on accessibility services like
+TalkBack and Explore by Touch, and try using your application using only directional controls.</li>
+</ul>
+
+<p>Generally, app developers get accessibility support for free, courtesy of
+the {@link android.view.View} and {@link android.view.ViewGroup}
+classes. However, some apps use custom view elements to provide a richer user experience. Such
+custom elements won't get the accessibility support that is provided by the standard Android UI
+elements. If this applies to your app, make sure that it exposes the custom-drawn UI element to
+Android accessibility services by implementing the
+{@link android.view.accessibility.AccessibilityNodeProvider} class.</p>
+
+<p>If the custom view element contains a single element, make it accessible by
+<a href="{@docRoot}guide/topics/ui/accessibility/apps.html#accessibility-methods">implementing
+accessibility API methods</a>.
+If the custom view contains elements that are not views themselves (for example, a
+{@link android.webkit.WebView}, make sure it implements the
+{@link android.view.accessibility.AccessibilityNodeProvider} class. For container views that
+extend an existing container implementation
+(for example, a {@link android.widget.ListView}), implementing
+{@link android.view.accessibility.AccessibilityNodeProvider} is not necessary.</p>
+
+<p>For more information about implementing and testing accessibility, see
+<a href="{@docRoot}guide/topics/ui/accessibility/apps.html">Making Applications Accessible</a>.</p>
+
+<h2 id="build">Create a UI Automator Test Class</h2>
+
+<p>To build a UI Automator test, create a class that extends
+{@link android.test.InstrumentationTestCase}. Implement the following programming model in your
+UI Automator test class:</p>
+
+<ol>
+<li>Get a
+  <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+  object to access the device you want to test, by calling the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#getInstance(android.app.Instrumentation)">
+{@code getInstance()}</a>
+method and passing it an {@link android.app.Instrumentation} object as the argument.</li>
+<li>Get a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+object to access a UI component that is displayed on the device
+	(for example, the current view in the foreground), by calling the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">
+  {@code findObject()}</a>
+method.
+</li>
+<li>Simulate a specific user interaction to perform on that UI component, by calling a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+method; for example, call
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#performMultiPointerGesture(android.view.MotionEvent.PointerCoords[]...)">
+  {@code performMultiPointerGesture()}</a>
+to simulate a multi-touch gesture, and
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">{@code setText()}</a>
+to edit a text field. You can call on the APIs in steps 2 and 3 repeatedly as necessary to test
+more complex user interactions that involve multiple UI components or sequences of user actions.</li>
+<li>Check that the UI reflects the expected state or behavior, after these user interactions are
+	performed. </li>
+</ol>
+
+<p>These steps are covered in more detail in the sections below.</p>
+
+<h3 id="accessing-ui-components">Accessing UI Components</h3>
+<p>The
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+  object is the primary way you access and manipulate the state of the
+device. In your tests, you can call
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+methods to check for the state of various properties, such as current orientation or display size.
+Your test can use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+object to perform device-level actions, such as forcing the device into a specific rotation,
+pressing D-pad hardware buttons, and pressing the Home and Menu buttons.</p>
+
+<p>It’s good practice to start your test from the Home screen of the device. From the Home screen
+(or some other starting location you’ve chosen in the device), you can call the methods provided by
+the UI Automator API to select and interact with specific UI elements. </p>
+
+<p>The following code snippet shows how your test might get an instance of
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+and simulate a Home button press:</p>
+
+<pre>
+import android.test.InstrumentationTestCase;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.By;
+
+public class CalculatorUiTest extends InstrumentationTestCase {
+
+    private UiDevice mDevice;
+
+    public void setUp() {
+        // Initialize UiDevice instance
+        mDevice = UiDevice.getInstance(getInstrumentation());
+
+        // Start from the home screen
+        mDevice.pressHome();
+        mDevice.wait(Until.hasObject(By.pkg(getHomeScreenPackage()).depth(0)),
+    }
+}
+</pre>
+
+<p>Use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">{@code findObject()}</a>
+method to retrieve a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+which represents a view that matches a given selector criteria. You can reuse the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+instances that you have created in other parts of your app testing, as needed. Note that the
+UI Automator test framework searches the current display for a match every time your test uses a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+instance to click on a UI element or query a property.</p>
+
+<p>The following snippet shows how your test might construct
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+instances that represent a Cancel button and a OK button in an app.</p>
+
+<pre>
+UiObject cancelButton = mDevice.findObject(new UiSelector()
+        .text("Cancel"))
+        .className("android.widget.Button"));
+UiObject okButton = mDevice.findObject(new UiSelector()
+        .text("OK"))
+        .className("android.widget.Button"));
+
+// Simulate a user-click on the OK button, if found.
+if(okButton.exists() &#38;&#38; okButton.isEnabled()) {
+    okButton.click();
+}
+</pre>
+
+<h4 id="specifying-selector">Specifying a selector</h4>
+<p>If you want to access a specific UI component in an app, use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
+class. This class represents a query for specific elements in the
+currently displayed UI. </p>
+
+<p>If more than one matching element is found, the first matching element in the layout hierarchy
+is returned as the target
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>.
+When constructing a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>,
+you can chain together multiple properties to refine your search. If no matching UI element is
+found, a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObjectNotFoundException.html">
+{@code UiAutomatorObjectNotFoundException}</a> is thrown. </p>
+
+<p>You can use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html#childSelector(android.support.test.uiautomator.UiSelector)">{@code childSelector()}</a>
+method to nest multiple
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
+instances. For example, the following code example shows how your test might specify a search to
+find the first {@link android.widget.ListView} in the currently displayed UI, then search within that
+{@link android.widget.ListView} to find a UI element with the text property Apps.</p>
+
+<pre>
+UiObject appItem = new UiObject(new UiSelector()
+        .className("android.widget.ListView")
+        .instance(1)
+        .childSelector(new UiSelector()
+        .text("Apps")));
+</pre>
+
+<p>As a best practice, when specifying a selector, you should use a Resource ID (if one is assigned
+to a UI element) instead of a text element or content-descriptor. Not all elements have a text
+element (for example, icons in a toolbar). Text selectors are brittle and can lead to test failures
+if there are minor changes to the UI. They may also not scale across different languages; your text
+selectors may not match translated strings.</p>
+
+<p>It can be useful to specify the object state in your selector criteria. For example, if you want
+to select a list of all checked elements so that you can uncheck them, call the
+<a href="{@docRoot}reference/android/support/test/uiautomator/By.html#checked(boolean)">
+{@code checked()}</a>
+method with the argument set to {@code true}.</p>
+
+<h3 id="performing-actions">Performing Actions</h3>
+
+<p>Once your test has obtained a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+object, you can call the methods in the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+class to perform user interactions on the UI component represented by that
+object. You can specify such actions as:</p>
+
+<ul>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#click()">
+  {@code click()}</a>
+: Clicks the center of the visible bounds of the UI element.</li>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#dragTo(int, int, int)">
+  {@code dragTo()}</a>
+: Drags this object to arbitrary coordinates.</li>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">
+  {@code setText()}</a>
+: Sets the text in an editable field, after clearing the field's content.
+Conversely, the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#clearTextField()">
+  {@code clearTextField()}</a>
+method clears the existing text in an editable field.</li>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeUp(int)">
+  {@code swipeUp()}</a>
+: Performs the swipe up action on the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>.
+Similarly, the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeDown(int)">
+  {@code swipeDown()}</a>,
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeLeft(int)">
+  {@code swipeLeft()}</a>, and
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeRight(int)">
+  {@code swipeRight()}</a>
+methods perform corresponding actions.</li>
+</ul>
+
+<p>The UI Automator testing framework allows you to send an
+{@link android.content.Intent}
+or launch an {@link android.app.Activity}
+without using shell commands, by getting a
+{@link android.content.Context}
+object through
+{@link android.app.Instrumentation#getContext() getContext()}.</p>
+
+<p>The following snippet shows how your test can use an
+{@link android.content.Intent} to launch the app under test. This approach is useful when you are
+only interested in testing the calculator app, and don't care about the launcher.</p>
+
+<pre>
+public void setUp() {
+    ...
+
+    // Launch a simple calculator app
+    Context context = getInstrumentation().getContext();
+    Intent intent = context.getPackageManager()
+            .getLaunchIntentForPackage(CALC_PACKAGE);
+    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            // Clear out any previous instances
+    context.startActivity(intent);
+    mDevice.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
+}
+</pre>
+
+<h4 id="actions-on-collections">Performing actions on collections</h4>
+
+<p>Use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
+  {@code UiCollection}</a>
+class if you want to simulate user interactions on a
+collection of items (for example, songs in a music album or a list of emails in an Inbox). To
+create a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
+  {@code UiCollection}</a>
+object, specify a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
+that searches for a
+UI container or a wrapper of other child UI elements, such as a layout view that contains child UI
+elements.</p>
+
+<p>The following code snippet shows how your test might construct a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
+  {@code UiCollection}</a>
+to represent a video album that is displayed within a {@link android.widget.FrameLayout}:</p>
+
+<pre>
+UiCollection videos = new UiCollection(new UiSelector()
+        .className("android.widget.FrameLayout"));
+
+// Retrieve the number of videos in this collection:
+int count = videos.getChildCount(new UiSelector()
+        .className("android.widget.LinearLayout"));
+
+// Find a specific video and simulate a user-click on it
+UiObject video = videos.getChildByText(new UiSelector()
+        .className("android.widget.LinearLayout"), "Cute Baby Laughing");
+video.click();
+
+// Simulate selecting a checkbox that is associated with the video
+UiObject checkBox = video.getChild(new UiSelector()
+        .className("android.widget.Checkbox"));
+if(!checkBox.isSelected()) checkbox.click();
+</pre>
+
+<h4 id="actions-on-scrollable-views">Performing actions on scrollable views</h4>
+<p>Use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiScrollable.html">
+  {@code UiScrollable}</a>
+class to simulate vertical or horizontal scrolling across a display. This technique is helpful when
+a UI element is positioned off-screen and you need to scroll to bring it into view.</p>
+
+<p>The following code snippet shows how to simulate scrolling down the Settings menu and clicking
+on an About tablet option:</p>
+
+<pre>
+UiScrollable settingsItem = new UiScrollable(new UiSelector()
+        .className("android.widget.ListView"));
+UiObject about = settingsItem.getChildByText(new UiSelector()
+        .className("android.widget.LinearLayout"), "About tablet");
+about.click();
+</pre>
+
+<h3 id="verifying-results">Verifying Results</h3>
+<p>The {@link android.test.InstrumentationTestCase} extends {@link junit.framework.TestCase}, so
+you can use standard JUnit <a href="http://junit.org/javadoc/latest/org/junit/Assert.html"
+class="external-link">{@code Assert}</a> methods to test
+that UI components in the app return the expected results. </p>
+
+<p>The following snippet shows how your test can locate several buttons in a calculator app, click
+on them in order, then verify that the correct result is displayed.</p>
+
+<pre>
+private static final String CALC_PACKAGE = "com.myexample.calc";
+
+public void testTwoPlusThreeEqualsFive() {
+    // Enter an equation: 2 + 3 = ?
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("two")).click();
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("plus")).click();
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("three")).click();
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("equals")).click();
+
+    // Verify the result = 5
+    UiObject result = mDevice.findObject(By.res(CALC_PACKAGE, "result"));
+    assertEquals("5", result.getText());
+}
+</pre>
+
+<h2 id="run">Run UI Automator Tests on a Device or Emulator</h2>
+<p>UI Automator tests are based on the {@link android.app.Instrumentation} class. The
+<a href="https://developer.android.com/tools/building/plugin-for-gradle.html">
+  Android Plug-in for Gradle</a>
+provides a default directory ({@code src/androidTest/java}) for you to store the instrumented test
+classes and test suites that you want to run on a device. The plug-in compiles the test
+code in that directory and then executes the test app using a test runner class. You are
+strongly encouraged to use the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+class provided in the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
+as your default test runner. </p>
+
+<p>To run UI Automator tests in your Gradle project:</p>
+
+<ol>
+<li>Specify
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+as the default test instrumentation runner in your {@code build.gradle} file:
+<pre>
+android {
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+}</pre>
+</li>
+<li>Run your tests from the command-line by calling the {@code connectedCheck}
+  (or {@code cC}) task:
+<pre>./gradlew cC</pre>
+</li>
+</ol>
\ No newline at end of file
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 11ae1a6..3ee7ab7 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -998,10 +998,25 @@
            Building TV Games</a>
       </li>
 
-      <li>
-        <a href="<?cs var:toroot ?>training/tv/tif/index.html"
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/tv/tif/index.html"
            description="How to build Live TV apps.">
            Building Live TV Apps</a>
+        </div>
+        <ul>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/tvinput.html">
+              Developing a TV Input Service</a>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/channel.html">
+              Working with Channel Data</a>
+          </li>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/ui.html">
+              Managing User Interaction</a>
+          </li>
+        </ul>
       </li>
 
       <li>
@@ -1825,6 +1840,24 @@
         </ul>
       </li>
     </ul>
+    <ul>
+      <li class="nav-section">
+      <div class="nav-section-header"><a href="<?cs var:toroot ?>training/testing/ui-testing/index.html"
+         description="How to automate your user interface tests for Android apps.">
+            Automating UI Tests
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/testing/ui-testing/espresso-testing.html">
+            <span class="en">Testing UI for a Single App</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/testing/ui-testing/uiautomator-testing.html">
+            <span class="en">Testing UI for Multiple Apps</span>
+          </a>
+          </li>
+        </ul>
+      </li>
+    </ul>
   </li>
   <!-- End best Testing -->
 
diff --git a/docs/html/training/tv/tif/channel.jd b/docs/html/training/tv/tif/channel.jd
new file mode 100644
index 0000000..999f1ca
--- /dev/null
+++ b/docs/html/training/tv/tif/channel.jd
@@ -0,0 +1,239 @@
+page.title=Working with Channel Data
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#permission">Get Permission</a></li>
+    <li><a href="#register">Register Channels in the Database</a></li>
+    <li><a href="#update">Update Channel Data</a></li>
+  </ol>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>Your TV input must provide Electronic Program Guide (EPG) data for at least one channel in its
+setup activity. You should also periodically update that data, with consideration for the size of
+the update and the processing thread that handles it. This lesson discusses creating and updating
+channel and program data on the system database with these considerations in mind.</p>
+
+<p>&nbsp;</p>
+
+<h2 id="permission">Get Permission</h2>
+
+<p>In order for your TV input to work with EPG data, it must declare the
+read and write permissions in its Android manifest file as follows:</p>
+
+<pre>
+&lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
+&lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
+</pre>
+
+<h2 id="register">Register Channels in the Database</h2>
+
+<p>The Android TV system database maintains records of channel data for TV inputs. In your setup
+activity, for each of your channels, you must map your channel data to the following fields of the
+{@link android.media.tv.TvContract.Channels} class:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NAME} - the displayed name of the
+  channel</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER} - the displayed channel
+  number</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_INPUT_ID} - the ID of the TV input service</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_TYPE} - the channel's service type</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TYPE} - the channel's broadcast standard
+  type</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_VIDEO_FORMAT} - the default video format
+  for the channel</li>
+</ul>
+
+<p>Although the TV input framework is generic enough to handle both traditional broadcast and
+over-the-top (OTT) content without any distinction, you may want to define the following columns in
+addition to those above to better identify traditional broadcast channels:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_ORIGINAL_NETWORK_ID} - the television
+  network ID</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_ID} - the service ID</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TRANSPORT_STREAM_ID} - the transport stream
+  ID</li>
+</ul>
+
+<p>For internet streaming based TV inputs, assign your own values to the above accordingly so that
+each channel can be identified uniquely.</p>
+
+<p>Pull your channel metadata (in XML, JSON, or whatever) from your backend server, and in your setup
+activity map the values to the system database as follows:</p>
+
+<pre>
+ContentValues values = new ContentValues();
+
+values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.mNumber);
+values.put(Channels.COLUMN_DISPLAY_NAME, channel.mName);
+values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.mOriginalNetworkId);
+values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.mTransportStreamId);
+values.put(Channels.COLUMN_SERVICE_ID, channel.mServiceId);
+values.put(Channels.COLUMN_VIDEO_FORMAT, channel.mVideoFormat);
+
+Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+</pre>
+
+<p>In the example above, <code>channel</code> is an object which holds channel metadata from the
+backend server.</p>
+
+<h3 id="art">Present Channel and Program Information</h2>
+
+<p>The system TV app presents channel and program information to users as they flip through channels,
+as shown in figure 1. To make sure the channel and program information works with the system TV app's
+channel and program information presenter, follow the guidelines below.</p>
+
+<ol>
+<li><strong>Channel number</strong> ({@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER})
+<li><strong>Icon</strong>
+(<a href="guide/topics/manifest/application-element.html#icon"><code>android:icon</code></a> in the
+TV input's manifest)</li>
+<li><strong>Program description</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_SHORT_DESCRIPTION})
+<li><strong>Program title</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_TITLE})</li>
+<li><strong>Channel logo</strong> ({@link android.media.tv.TvContract.Channels.Logo})
+  <ul>
+    <li>Use the color #EEEEEE to match the surrounding text</li>
+    <li>Don't include padding
+  </ul></li>
+<li><strong>Poster art</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_POSTER_ART_URI})
+  <ul>
+    <li>Aspect ratio between 16:9 and 4:3</li>
+  </ul>
+</ol>
+
+<img src="{@docRoot}images/tv/channel-info.png" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> The system TV app channel and program information presenter.
+</p>
+
+<p>The system TV app provides the same information through the program guide, including poster art,
+as shown in figure 2.</p>
+
+<img src="{@docRoot}images/tv/prog-guide.png" id="figure2">
+<p class="img-caption">
+  <strong>Figure 2.</strong> The system TV app program guide.
+</p>
+
+<h2 id="update">Update Channel Data</h2>
+
+<p>When updating existing channel data, use the
+{@link android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues,
+java.lang.String, java.lang.String[]) update()}
+method instead of deleting and re-adding the data. You can identify the current version of the data
+by using {@link android.media.tv.TvContract.Channels#COLUMN_VERSION_NUMBER Channels.COLUMN_VERSION_NUMBER}
+and {@link android.media.tv.TvContract.Programs#COLUMN_VERSION_NUMBER Programs.COLUMN_VERSION_NUMBER}
+when choosing the records to update.</p>
+
+<p class="note"><strong>Note:</strong> Adding channel data to the {@link android.content.ContentProvider}
+can take time. Only add current programs (those within two hours of the current time) when you update,
+and use a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">Sync Adapter</a> to
+update the rest of the channel data in the background. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV Live TV Sample App</a> for an example.</p>
+
+<h3 id="batch">Batch Loading Channel Data</h3>
+
+<p>When updating the system database with a large amount of channel data, use the {@link android.content.ContentResolver}
+{@link android.content.ContentResolver#applyBatch applyBatch()}
+or
+{@link android.content.ContentResolver#bulkInsert(android.net.Uri, android.content.ContentValues[]) bulkInsert()}
+method. Here's an example using {@link android.content.ContentResolver#applyBatch applyBatch()}:<p>
+
+<pre>
+ArrayList&lt;ContentProviderOperation&gt; ops = new ArrayList&lt;&gt;();
+int programsCount = mChannelInfo.mPrograms.size();
+for (int j = 0; j &lt; programsCount; ++j) {
+    ProgramInfo program = mChannelInfo.mPrograms.get(j);
+    ops.add(ContentProviderOperation.newInsert(
+            TvContract.Programs.CONTENT_URI)
+            .withValues(programs.get(j))
+            .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
+                    programStartSec * 1000)
+            .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
+                    (programStartSec + program.mDurationSec) * 1000)
+            .build());
+    programStartSec = programStartSec + program.mDurationSec;
+    if (j % 100 == 99 || j == programsCount - 1) {
+        try {
+            <strong>getContentResolver().applyBatch(TvContract.AUTHORITY, ops);</strong>
+        } catch (RemoteException | OperationApplicationException e) {
+            Log.e(TAG, "Failed to insert programs.", e);
+            return;
+        }
+        ops.clear();
+    }
+}
+</pre>
+
+<h3 id="async">Processing Channel Data Asynchronously</h3>
+
+<p>Data manipulation, such as fetching a stream from the server or accessing the database, should
+not block the UI thread. Using an {@link android.os.AsyncTask} is one
+way to perform updates asynchronously.  For example, when loading channel info from a backend server,
+you can use {@link android.os.AsyncTask} as follows:</p>
+
+<pre>
+private static class LoadTvInputTask extends AsyncTask&lt;Uri, Void, Void>&gt; {
+
+    private Context mContext;
+
+    public LoadTvInputTask(Context context) {
+        mContext = context;
+    }
+
+    &#64;Override
+    protected Void doInBackground(Uri... uris) {
+        try {
+            fetchUri(uris[0]);
+        } catch (IOException e) {
+          Log.d(“LoadTvInputTask”, “fetchUri error”);
+        }
+        return null;
+    }
+
+    private void fetchUri(Uri videoUri) throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = mContext.getContentResolver().openInputStream(videoUri);
+            XmlPullParser parser = Xml.newPullParser();
+            try {
+                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+                parser.setInput(inputStream, null);
+                sTvInput = ChannelXMLParser.parseTvInput(parser);
+                sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+        } finally {
+            if (inputStream != null) {
+                inputStream.close();
+            }
+        }
+    }
+}
+</pre>
+
+<p>If you need to update EPG data on a regular basis, consider using
+a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">
+Sync Adapter</a> or {@link android.app.job.JobScheduler} to run the update process during idle time,
+such as every day at 3:00 a.m. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV live TV sample app</a> for an example.</p>
+
+<p>Other techniques to separate the data update tasks from the UI thread include using the
+{@link android.os.HandlerThread} class, or you may implement your own using {@link android.os.Looper}
+and {@link android.os.Handler} classes.  See <a href="{@docRoot}guide/components/processes-and-threads.html">
+Processes and Threads</a> for more information.</p>
\ No newline at end of file
diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd
index 9c10850..5739294 100644
--- a/docs/html/training/tv/tif/index.jd
+++ b/docs/html/training/tv/tif/index.jd
@@ -1,17 +1,26 @@
 page.title=Building Live TV Apps
 page.tags=tv, tif
 helpoutsWidget=true
-page.article=true
+startpage=true
 
 @jd:body
 
 <div id="tb-wrapper">
 <div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+  <ul>
+    <li>Android 5.0 (API level 21) or higher</li>
+  </ul>
   <h2>You should also read</h2>
   <ul>
     <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
       android.media.tv</a></li>
   </ul>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
 </div>
 </div>
 
@@ -44,6 +53,17 @@
   Building a TV input service for your content can help make it more accessible on TV devices.
 </p>
 
-<p>For more information about TV Input Framework, see the
-<a href="{@docRoot}reference/android/media/tv/package-summary.html">android.media.tv</a>
-reference.</p>
+<h2>Topics</h2>
+
+<dl>
+  <dt><b><a href="tvinput.html">Developing a TV Input Service</a></b></dt>
+    <dd>Learn how to develop a TV input service, which works with the system TV app.</dd>
+
+  <dt><b><a href="channel.html">Working with Channel Data</a></b></dt>
+    <dd>Learn how to describe channel and program data for the system.</dd>
+
+  <dt><b><a href="ui.html">Managing User Interaction</a></b></dt>
+    <dd>Learn how to present overlays, manage content availability, and handle content selection.</dd>
+</dl>
+
+
diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
new file mode 100644
index 0000000..91f8ded
--- /dev/null
+++ b/docs/html/training/tv/tif/tvinput.jd
@@ -0,0 +1,177 @@
+page.title=Developing a TV Input Service
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
+    <li><a href="#tvinput">Define Your TV Input Service</a></li>
+    <li><a href="#setup">Define Setup and Settings Activities</a></li>
+  </ol>
+  <h2>You should also read</h2>
+  <ul>
+    <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
+      android.media.tv</a></li>
+    <li><a class="external-lin" href="http://source.android.com/devices/tv/index.html">
+      TV Input Framework</a></li>
+  </ul>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>A TV input service represents a media stream source, and lets you present your media content in a
+linear, broadcast TV fashion as channels and programs. With the TV input service, you can provide
+parental controls, program guide information, and content ratings. The TV input service works
+with the Android system TV app, developed for the device and immutable by third-party apps, which
+ultimately controls and presents content on the TV. See
+<a class="external-link" href="http://source.android.com/devices/tv/index.html">
+TV Input Framework</a> for more information about the framework architecture and its components.</p>
+
+<p>To develop a TV input service, you implement the following components:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
+  the TV input</li>
+  <li>{@link android.media.tv.TvInputService.Session} maintains the TV input state and communicates
+  with the hosting app</li>
+  <li>{@link android.media.tv.TvContract} describes the channels and programs available to the TV
+  input</li>
+  <li>{@link android.media.tv.TvContract.Channels} represents information about a TV channel</li>
+  <li>{@link android.media.tv.TvContract.Programs} describes a TV program with data such as program
+  title and start time</li>
+  <li>{@link android.media.tv.TvTrackInfo} represents an audio, video, or subtitle track</li>
+  <li>{@link android.media.tv.TvContentRating} describes a content rating, allows for custom content
+  rating schemes</li>
+  <li>{@link android.media.tv.TvInputManager} provides an API to the system TV app and manages
+  the interaction with TV inputs and apps</li>
+</ul>
+
+<h2 id="manifest">Declare Your TV Input Service in the Manifest</h2>
+
+<p>Your app manifest must declare your {@link android.media.tv.TvInputService}. Within that
+declaration, specify the {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
+service to connect the TV input to the system. A system service (<code>TvInputManagerService</code>)
+performs the binding and has that permission. The system TV app sends requests to TV input services
+via the {@link android.media.tv.TvInputManager} interface. The service declaration must also
+include an intent filter that specifies the {@link android.media.tv.TvInputService}
+as the action to perform with the intent. Also within the service declaration, declare the service
+meta data in a separate XML resource. The service declaration, the intent filter and the service
+meta data are described in the following example.</p>
+
+<pre>
+&lt;service android:name="com.example.sampletvinput.SampleTvInput"
+    android:label="@string/sample_tv_input_label"
+    android:permission="android.permission.BIND_TV_INPUT"&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.media.tv.TvInputService" /&gt;
+    &lt;/intent-filter&gt;
+    &lt;meta-data android:name="android.media.tv.input"
+      android:resource="@xml/sample_tv_input" /&gt;
+&lt;/service&gt;
+</pre>
+
+<p>Define the service meta data in separate XML file, as shown in the following example. The service
+meta data must include a setup interface that describes the TV input's initial configuration and
+channel scan. Also, the service meta data may (optionally) describe a settings activity for users to
+modify the TV input's behavior. The service meta data file is located in the XML resources directory
+for your application and must match the name of the resource in the manifest. Using the example
+manifest entries above, you would create an XML file in the location
+<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
+
+<pre>
+&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
+  &lt;!-- Required: activity for setting up the input --&gt;
+  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity"
+  &lt;!-- Optional: activity for controlling the settings --&gt;
+  android:settingsActivity="com.example.sampletvinput.SampleTvInputSettingsActivity" /&gt;
+</pre>
+
+<h2 id="tvinput">Define Your TV Input Service</h2>
+
+<div class="figure">
+<img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong>TvInputService lifecycle.</p>
+</div>
+
+<p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
+{@link android.media.tv.TvInputService} implementation is a
+<a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
+(<code>TvInputManagerService</code>) is the client that binds to it. The service life cycle methods
+you need to implement are illustrated in figure 1.</p>
+
+<p>The {@link android.app.Service#onCreate()} method initializes and starts the
+{@link android.os.HandlerThread} which provides a process thread separate from the UI thread to
+handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()}
+method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle
+the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED}
+and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These
+actions describe system intents fired when the user changes the parental control settings, and when
+there is a change on the list of blocked ratings.</p>
+
+<pre>
+&#64;Override
+public void onCreate() {
+    super.onCreate();
+    mHandlerThread = new HandlerThread(getClass()
+      .getSimpleName());
+    mHandlerThread.start();
+    mDbHandler = new Handler(mHandlerThread.getLooper());
+    mHandler = new Handler();
+    mCaptioningManager = (CaptioningManager)
+      getSystemService(Context.CAPTIONING_SERVICE);
+
+    setTheme(android.R.style.Theme_Holo_Light_NoActionBar);
+
+    mSessions = new ArrayList&lt;BaseTvInputSessionImpl&gt;();
+    IntentFilter intentFilter = new IntentFilter();
+    intentFilter.addAction(TvInputManager
+      .ACTION_BLOCKED_RATINGS_CHANGED);
+    intentFilter.addAction(TvInputManager
+      .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
+    registerReceiver(mBroadcastReceiver, intentFilter);
+}
+</pre>
+
+<p> See <a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> for more information about working with blocked content and providing
+parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that
+you may want to handle in your TV input service.</p>
+
+<p>The {@link android.media.tv.TvInputService} creates a
+{@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
+to handle player state changes. With {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
+the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
+video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
+for more information about working with {@link android.view.Surface} to render video.</p>
+
+<p>The {@link android.media.tv.TvInputService.Session} handles the
+{@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
+event when the user selects a channel, and notifies the system TV app for changes in the content and
+content meta data. These <code>notify()</code>code> methods are described in
+<a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> and <a href="training/tv/tif/ui.html#track">Handle Track Selection</a> further
+in this training.</p>
+
+<h2 id="setup">Define Setup and Settings Activities</h2>
+
+<p>The system TV app works with the setup and settings activities you define for your TV input. The
+setup activity is required and must provide at least one channel record for the system database. The
+system TV app will invoke the setup activity when it cannot find a channel for the TV input.
+<p>The setup activity describes to the system TV app the channels made available through the TV
+input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
+and Updating Channel Data</a>.</p>
+
+<p>The settings activity is optional. You can define a settings activity to turn on parental
+controls, enable closed captions, set the display attributes, and so forth.</p>
+
+
diff --git a/docs/html/training/tv/tif/ui.jd b/docs/html/training/tv/tif/ui.jd
new file mode 100644
index 0000000..6ead3db
--- /dev/null
+++ b/docs/html/training/tv/tif/ui.jd
@@ -0,0 +1,304 @@
+page.title=Managing User Interaction
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#surface">Integrate Player with Surface</a></li>
+    <li><a href="#overlay">Use an Overlay</a></li>
+    <li><a href="#control">Control Content</a></li>
+    <li><a href="#track">Handle Track Selection</a></li>
+  </ol>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>In the live TV experience the user changes channels and is presented with
+channel and program information briefly before the information disappears. Other types of information,
+such as messages ("DO NOT ATTEMPT AT HOME"), subtitles, or ads may need to persist. As with any TV
+app, such information should not interfere with the program content playing on the screen.</p>
+
+<img src="{@docRoot}images/tv/do-not-attempt.png" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> An overlay message in a live TV app.
+</p>
+
+<p>Also consider whether certain program content should be presented, given the
+content's rating and parental control settings, and how your app behaves and informs the user when
+content is blocked or unavailable. This lesson describes how to develop your TV input's user
+experience for these considerations.</p>
+
+<h2 id="surface">Integrate Player with Surface</h2>
+
+<p>Your TV input must render video onto a {@link android.view.Surface} object, which is passed by
+the {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) TvInputService.Session.onSetSurface()}
+method. Here's an example of how to use a {@link android.media.MediaPlayer} instance for playing
+content in the {@link android.view.Surface} object:</p>
+
+<pre>
+&#64;Override
+public boolean onSetSurface(Surface surface) {
+    if (mPlayer != null) {
+        mPlayer.setSurface(surface);
+    }
+    mSurface = surface;
+    return true;
+}
+
+&#64;Override
+public void onSetStreamVolume(float volume) {
+    if (mPlayer != null) {
+        mPlayer.setVolume(volume, volume);
+    }
+    mVolume = volume;
+}
+</pre>
+
+<p>Similarly, here's how to do it using <a href="{@docRoot}guide/topics/media/exoplayer.html">
+ExoPlayer</a>:</p>
+
+<pre>
+&#64;Override
+public boolean onSetSurface(Surface surface) {
+    if (mPlayer != null) {
+        mPlayer.sendMessage(mVideoRenderer,
+                MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
+                surface);
+    }
+    mSurface = surface;
+    return true;
+}
+
+&#64;Override
+public void onSetStreamVolume(float volume) {
+    if (mPlayer != null) {
+        mPlayer.sendMessage(mAudioRenderer,
+                MediaCodecAudioTrackRenderer.MSG_SET_VOLUME,
+                volume);
+    }
+    mVolume = volume;
+}
+</pre>
+
+<h2 id="overlay">Use an Overlay</h2>
+
+<p>Use an overlay to display subtitles, messages, ads or MHEG-5 data broadcasts. By default, the
+overlay is disabled. You can enable it when you create the session by calling
+{@link android.media.tv.TvInputService.Session#setOverlayViewEnabled(boolean) TvInputService.Session.setOverlayViewEnabled(true)},
+as in the following example:</p>
+
+<pre>
+&#64;Override
+public final Session onCreateSession(String inputId) {
+    BaseTvInputSessionImpl session = onCreateSessionInternal(inputId);
+    session.setOverlayViewEnabled(true);
+    mSessions.add(session);
+    return session;
+}
+</pre>
+
+<p>Use a {@link android.view.View} object for the overlay, returned from {@link android.media.tv.TvInputService.Session#onCreateOverlayView() TvInputService.Session.onCreateOverlayView()}, as shown here:</p>
+
+<pre>
+&#64;Override
+public View onCreateOverlayView() {
+    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+    View view = inflater.inflate(R.layout.overlayview, null);
+    mSubtitleView = (SubtitleView) view.findViewById(R.id.subtitles);
+
+    // Configure the subtitle view.
+    CaptionStyleCompat captionStyle;
+    float captionTextSize = getCaptionFontSize();
+    captionStyle = CaptionStyleCompat.createFromCaptionStyle(
+            mCaptioningManager.getUserStyle());
+    captionTextSize *= mCaptioningManager.getFontScale();
+    mSubtitleView.setStyle(captionStyle);
+    mSubtitleView.setTextSize(captionTextSize);
+    return view;
+}
+</pre>
+
+<p>The layout definition for the overlay might look something like this:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+
+    &lt;com.google.android.exoplayer.text.SubtitleView
+        android:id="@+id/subtitles"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp"
+        android:layout_marginBottom="32dp"
+        android:visibility="invisible"/&gt;
+&lt;/FrameLayout&gt;
+</pre>
+
+<h2 id="control">Control Content</h2>
+
+<p>When the user selects a channel, your TV input handles the {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri)
+onTune()} callback in the {@link android.media.tv.TvInputService.Session} object. The system TV
+app's parental controls determine what content displays, given the content rating.
+The following sections describe how to manage channel and program selection using the
+{@link android.media.tv.TvInputService.Session} <code>notify</code> methods that
+communicate with the system TV app.</p>
+
+<h3 id="unavailable">Make Video Unavailable</h3>
+
+<p>When the user changes the channel, you want to make sure the screen doesn't display any stray
+video artifacts before your TV input renders the content. When you call {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) TvInputService.Session.onTune()},
+you can prevent the video from being presented by calling {@link android.media.tv.TvInputService.Session#notifyVideoUnavailable(int) TvInputService.Session.notifyVideoUnavailable()}
+and passing the {@link android.media.tv.TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING} constant, as
+shown in the following example.</p>
+
+<pre>
+&#64;Override
+public boolean onTune(Uri channelUri) {
+    if (mSubtitleView != null) {
+        mSubtitleView.setVisibility(View.INVISIBLE);
+    }
+    notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+    mUnblockedRatingSet.clear();
+
+    mDbHandler.removeCallbacks(mPlayCurrentProgramRunnable);
+    mPlayCurrentProgramRunnable = new PlayCurrentProgramRunnable(channelUri);
+    mDbHandler.post(mPlayCurrentProgramRunnable);
+    return true;
+}
+</pre>
+
+<p>Then, when the content is rendered to the {@link android.view.Surface}, you call
+{@link android.media.tv.TvInputService.Session#notifyVideoAvailable() TvInputService.Session.notifyVideoAvailable()}
+to allow the video to display, like so:</p>
+
+<pre>
+&#64;Override
+public void onDrawnToSurface(Surface surface) {
+    mFirstFrameDrawn = true;
+    notifyVideoAvailable();
+}
+</pre>
+
+<p>This transition lasts only for fractions of a second, but presenting a blank screen is
+visually better than allowing the picture to flash odd blips and jitters.</p>
+
+<p>See also, <a href="#surface">Integrate Player with Surface</a> for more information about working
+with {@link android.view.Surface} to render video.</p>
+
+<h3 id="parental">Provide Parental Control</h3>
+
+<p>To determine if a given content is blocked by parental controls and content rating, you check the
+{@link android.media.tv.TvInputManager} class methods, {@link android.media.tv.TvInputManager#isParentalControlsEnabled()}
+and {@link android.media.tv.TvInputManager#isRatingBlocked(android.media.tv.TvContentRating)}. You
+might also want to make sure the content's {@link android.media.tv.TvContentRating} is included in a
+set of currently allowed content ratings. These considerations are shown in the following sample.</p>
+
+<pre>
+private void checkContentBlockNeeded() {
+    if (mCurrentContentRating == null || !mTvInputManager.isParentalControlsEnabled()
+            || !mTvInputManager.isRatingBlocked(mCurrentContentRating)
+            || mUnblockedRatingSet.contains(mCurrentContentRating)) {
+        // Content rating is changed so we don't need to block anymore.
+        // Unblock content here explicitly to resume playback.
+        unblockContent(null);
+        return;
+    }
+
+    mLastBlockedRating = mCurrentContentRating;
+    if (mPlayer != null) {
+        // Children restricted content might be blocked by TV app as well,
+        // but TIF should do its best not to show any single frame of blocked content.
+        releasePlayer();
+    }
+
+    notifyContentBlocked(mCurrentContentRating);
+}
+</pre>
+
+<p>Once you have determined if the content should or should not be blocked, notify the system TV
+app by calling the
+{@link android.media.tv.TvInputService.Session} method {@link android.media.tv.TvInputService.Session#notifyContentAllowed() notifyContentAllowed()}
+or
+{@link android.media.tv.TvInputService.Session#notifyContentBlocked(android.media.tv.TvContentRating) notifyContentBlocked()}
+, as shown in the previous example.</p>
+
+<p>Use the {@link android.media.tv.TvContentRating} class to generate the system-defined string for
+the {@link android.media.tv.TvContract.Programs#COLUMN_CONTENT_RATING} with the
+<code><a href="{@docRoot}reference/android/media/tv/TvContentRating.html#createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String...)">TvContentRating.createRating()</a></code>
+method, as shown here:</p>
+
+<pre>
+TvContentRating rating = TvContentRating.createRating(
+    "com.android.tv",
+    "US_TV",
+    "US_TV_PG",
+    "US_TV_D", "US_TV_L");
+</pre>
+
+<h2 id="track">Handle Track Selection</h2>
+
+<p>The {@link android.media.tv.TvTrackInfo} class holds information about media tracks such
+as the track type (video, audio, or subtitle) and so forth. </p>
+
+<p>The first time your TV input session is able to get track information, it should call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">TvInputService.Session.notifyTracksChanged()</a></code> with a list of all tracks to update the system TV app.  When there
+is a change in track information, call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">notifyTracksChanged()</a></code>
+again to update the system.
+
+</p>
+
+<p>The system TV app provides an interface for the user to select a specific track if more than one
+track is available for a given track type; for example, subtitles in different languages. Your TV
+input responds to the
+{@link android.media.tv.TvInputService.Session#onSelectTrack(int, java.lang.String) onSelectTrack()}
+call from the system TV app by calling
+{@link android.media.tv.TvInputService.Session#notifyTrackSelected(int, java.lang.String) notifyTrackSelected()}
+, as shown in the following example. Note that when <code>null</code>
+is passed as the track ID, this <em>deselects</em> the track.</p>
+
+<pre>
+&#64;Override
+public boolean onSelectTrack(int type, String trackId) {
+    if (mPlayer != null) {
+        if (type == TvTrackInfo.TYPE_SUBTITLE) {
+            if (!mCaptionEnabled && trackId != null) {
+                return false;
+            }
+            mSelectedSubtitleTrackId = trackId;
+            if (trackId == null) {
+                mSubtitleView.setVisibility(View.INVISIBLE);
+            }
+        }
+        if (mPlayer.selectTrack(type, trackId)) {
+            notifyTrackSelected(type, trackId);
+            return true;
+        }
+    }
+    return false;
+}
+</pre>
+
+
+
+
+
+
+
diff --git a/docs/html/training/wearables/apps/voice.jd b/docs/html/training/wearables/apps/voice.jd
index 6d49319..3aef3c4 100644
--- a/docs/html/training/wearables/apps/voice.jd
+++ b/docs/html/training/wearables/apps/voice.jd
@@ -131,6 +131,17 @@
   </tr>
 
   <tr>
+    <td>Start stopwatch</td>
+    <td>"Ok Google, start stopwatch"</td>
+    <td>
+      <dl>
+        <dt>Action</dt>
+        <dd><code>com.google.android.wearable.action.STOPWATCH</code></dd>
+      </dl>
+   </td>
+  </tr>
+
+  <tr>
     <td>Start/Stop a bike ride</td>
     <td>"OK Google, start cycling"<br/><br/>"OK Google, start my bike ride"<br/><br/>"OK Google, stop cycling"</td>
     <td>
diff --git a/docs/html/training/wearables/watch-faces/drawing.jd b/docs/html/training/wearables/watch-faces/drawing.jd
index 3c5da34..60da5d5 100644
--- a/docs/html/training/wearables/watch-faces/drawing.jd
+++ b/docs/html/training/wearables/watch-faces/drawing.jd
@@ -377,7 +377,8 @@
 
 <ul>
 <li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color
-in ambient mode, so you should disable anti-aliasing.</li>
+in ambient mode, so you should disable anti-aliasing and bitmap filtering when the device switches
+to ambient mode.</li>
 <li>For devices that require burn-in protection, avoid using large blocks of white pixels in
 ambient mode and do not place content within 10 pixels of the edge of the screen, since the
 system shifts the content periodically to avoid pixel burn-in.</li>
@@ -385,7 +386,9 @@
 
 <p>For more information about low-bit ambient mode and burn-in protection, see
 <a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special
-Screens</a>.</p>
+Screens</a>. For more information on how to disable bitmap filtering, see
+<a href="{@docRoot}training/wearables/watch-faces/performance.html#BitmapFiltering">Bitmap
+Filtering</a>.</p>
 
 
 <h2 id="Modes">Respond to Changes Between Modes</h2>
diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd
index 68438fe..118bc6a 100644
--- a/docs/html/training/wearables/watch-faces/performance.jd
+++ b/docs/html/training/wearables/watch-faces/performance.jd
@@ -99,7 +99,9 @@
 setFilterBitmap()} method. <a href="#fig2">Figure 2</a> shows a magnified view of a clock hand with
 and without bitmap filtering.</p>
 
-
+<p class="note"><strong>Note:</strong> In low-bit ambient mode, the system does not reliably
+render the colors in the image for bitmap filtering to process successfully. When ambient mode is
+active, disable bitmap filtering.</p>
 
 <h2 id="OutDrawing">Move Expensive Operations Outside the Drawing Method</h2>
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index a3d8c92..72edf03 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -53,9 +53,9 @@
  * For more information about how to use ShapeDrawable, read the <a
  * href="{@docRoot}guide/topics/graphics/2d-graphics.html#shape-drawable">
  * Canvas and Drawables</a> document. For more information about defining a
- * ShapeDrawable in XML, read the <a href="{@docRoot}
- * guide/topics/resources/drawable-resource.html#Shape">Drawable Resources</a>
- * document.
+ * ShapeDrawable in XML, read the
+ * <a href="{@docRoot}guide/topics/resources/drawable-resource.html#Shape">
+ * Drawable Resources</a> document.
  * </p>
  * </div>
  *
diff --git a/native/android/Android.mk b/native/android/Android.mk
index cda38e0..6b77b4f 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -12,9 +12,10 @@
     looper.cpp \
     native_activity.cpp \
     native_window.cpp \
+    net.c \
     obb.cpp \
     sensor.cpp \
-    storage_manager.cpp
+    storage_manager.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
     liblog \
@@ -25,14 +26,17 @@
     libbinder \
     libui \
     libgui \
-    libandroid_runtime
+    libandroid_runtime \
+    libnetd_client \
 
 LOCAL_STATIC_LIBRARIES := \
     libstorage
 
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
-    frameworks/base/core/jni/android
+    frameworks/base/core/jni/android \
+    bionic/libc/dns/include \
+    system/netd/include \
 
 LOCAL_MODULE:= libandroid
 
diff --git a/native/android/net.c b/native/android/net.c
new file mode 100644
index 0000000..de4b90c
--- /dev/null
+++ b/native/android/net.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <android/multinetwork.h>
+#include <errno.h>
+#include <NetdClient.h>    // the functions that communicate with netd
+#include <resolv_netid.h>  // android_getaddrinfofornet()
+#include <stdlib.h>
+#include <sys/limits.h>
+
+
+static int getnetidfromhandle(net_handle_t handle, unsigned *netid) {
+    static const uint32_t k32BitMask = 0xffffffff;
+    // This value MUST be kept in sync with the corresponding value in
+    // the android.net.Network#getNetworkHandle() implementation.
+    static const uint32_t kHandleMagic = 0xfacade;
+
+    // Check for minimum acceptable version of the API in the low bits.
+    if (handle != NETWORK_UNSPECIFIED &&
+        (handle & k32BitMask) != kHandleMagic) {
+        return 0;
+    }
+
+    if (netid != NULL) {
+        *netid = ((handle >> (CHAR_BIT * sizeof(k32BitMask))) & k32BitMask);
+    }
+    return 1;
+}
+
+
+int android_setsocknetwork(net_handle_t network, int fd) {
+    unsigned netid;
+    if (!getnetidfromhandle(network, &netid)) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    int rval = setNetworkForSocket(netid, fd);
+    if (rval < 0) {
+        errno = -rval;
+        rval = -1;
+    }
+    return rval;
+}
+
+int android_setprocnetwork(net_handle_t network) {
+    unsigned netid;
+    if (!getnetidfromhandle(network, &netid)) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    int rval = setNetworkForProcess(netid);
+    if (rval < 0) {
+        errno = -rval;
+        rval = -1;
+    }
+    return rval;
+}
+
+int android_getaddrinfofornetwork(net_handle_t network,
+        const char *node, const char *service,
+        const struct addrinfo *hints, struct addrinfo **res) {
+    unsigned netid;
+    if (!getnetidfromhandle(network, &netid)) {
+        errno = EINVAL;
+        return EAI_SYSTEM;
+    }
+
+    return android_getaddrinfofornet(node, service, hints, netid, 0, res);
+}
diff --git a/obex/Android.mk b/obex/Android.mk
index fbfe9be..e7c1fd3 100644
--- a/obex/Android.mk
+++ b/obex/Android.mk
@@ -7,3 +7,14 @@
 LOCAL_MODULE:= javax.obex
 
 include $(BUILD_JAVA_LIBRARY)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE:= javax.obexstatic
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 75278b5..cc20d39 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (c) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -40,6 +41,8 @@
 import java.io.DataOutputStream;
 import java.io.ByteArrayOutputStream;
 
+import android.util.Log;
+
 /**
  * This class implements the <code>Operation</code> interface. It will read and
  * write data via puts and gets.
@@ -47,6 +50,10 @@
  */
 public final class ClientOperation implements Operation, BaseStream {
 
+    private static final String TAG = "ClientOperation";
+
+    private static final boolean V = ObexHelper.VDBG;
+
     private ClientSession mParent;
 
     private boolean mInputOpen;
@@ -75,6 +82,19 @@
 
     private boolean mEndOfBodySent;
 
+    private boolean mSendBodyHeader = true;
+    // A latch - when triggered, there is not way back ;-)
+    private boolean mSrmActive = false;
+
+    // Assume SRM disabled - until support is confirmed
+    // by the server
+    private boolean mSrmEnabled = false;
+    // keep waiting until final-bit is received in request
+    // to handle the case where the SRM enable header is in
+    // a different OBEX packet than the SRMP header.
+    private boolean mSrmWaitingForRemote = true;
+
+
     /**
      * Creates new OperationImpl to read and write data to a server
      * @param maxSize the maximum packet size
@@ -164,7 +184,7 @@
              * Since we are not sending any headers or returning any headers then
              * we just need to write and read the same bytes
              */
-            mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
+            mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null, false);
 
             if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
                 throw new IOException("Invalid response code from server");
@@ -215,6 +235,7 @@
         try {
             return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
         } catch (IOException e) {
+            if(V) Log.d(TAG, "Exception occured - returning null",e);
             return null;
         }
     }
@@ -236,6 +257,7 @@
                 return temp.longValue();
             }
         } catch (IOException e) {
+            if(V) Log.d(TAG,"Exception occured - returning -1",e);
             return -1;
         }
     }
@@ -408,7 +430,9 @@
     }
 
     /**
-     * Sends a request to the client of the specified type
+     * Sends a request to the client of the specified type.
+     * This function will enable SRM and set SRM active if the server
+     * response allows this.
      * @param opCode the request code to send to the client
      * @return <code>true</code> if there is more data to send;
      *         <code>false</code> if there is no more data to send
@@ -431,13 +455,16 @@
          * length, but it is a waste of resources if we can't send much of
          * the body.
          */
-        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
+        final int MINIMUM_BODY_LENGTH = 3;
+        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length + MINIMUM_BODY_LENGTH)
+                > mMaxPacketSize) {
             int end = 0;
             int start = 0;
             // split & send the headerArray in multiple packets.
 
             while (end != headerArray.length) {
                 //split the headerArray
+
                 end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
                         - ObexHelper.BASE_PACKET_LENGTH);
                 // can not split
@@ -459,7 +486,7 @@
 
                 byte[] sendHeader = new byte[end - start];
                 System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
-                if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput)) {
+                if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput, false)) {
                     return false;
                 }
 
@@ -470,12 +497,20 @@
                 start = end;
             }
 
+            // Enable SRM if it should be enabled
+            checkForSrm();
+
             if (bodyLength > 0) {
                 return true;
             } else {
                 return false;
             }
         } else {
+            /* All headers will fit into a single package */
+            if(mSendBodyHeader == false) {
+                /* As we are not to send any body data, set the FINAL_BIT */
+                opCode |= ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK;
+            }
             out.write(headerArray);
         }
 
@@ -499,11 +534,11 @@
              * (End of Body) otherwise, we need to send 0x48 (Body)
              */
             if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
-                    && ((opCode & 0x80) != 0)) {
-                out.write(0x49);
+                    && ((opCode & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) != 0)) {
+                out.write(HeaderSet.END_OF_BODY);
                 mEndOfBodySent = true;
             } else {
-                out.write(0x48);
+                out.write(HeaderSet.BODY);
             }
 
             bodyLength += 3;
@@ -517,12 +552,11 @@
 
         if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
             // only 0x82 or 0x83 can send 0x49
-            if ((opCode & 0x80) == 0) {
-                out.write(0x48);
+            if ((opCode & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
+                out.write(HeaderSet.BODY);
             } else {
-                out.write(0x49);
+                out.write(HeaderSet.END_OF_BODY);
                 mEndOfBodySent = true;
-
             }
 
             bodyLength = 3;
@@ -531,15 +565,20 @@
         }
 
         if (out.size() == 0) {
-            if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput)) {
+            if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput, mSrmActive)) {
                 return false;
             }
+            // Enable SRM if it should be enabled
+            checkForSrm();
             return returnValue;
         }
         if ((out.size() > 0)
-                && (!mParent.sendRequest(opCode, out.toByteArray(), mReplyHeader, mPrivateInput))) {
+                && (!mParent.sendRequest(opCode, out.toByteArray(),
+                        mReplyHeader, mPrivateInput, mSrmActive))) {
             return false;
         }
+        // Enable SRM if it should be enabled
+        checkForSrm();
 
         // send all of the output data in 0x48,
         // send 0x49 with empty body
@@ -549,6 +588,35 @@
         return returnValue;
     }
 
+    private void checkForSrm() throws IOException {
+        Byte srmMode = (Byte)mReplyHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
+        if(mParent.isSrmSupported() == true && srmMode != null
+                && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
+            mSrmEnabled = true;
+        }
+        /**
+         * Call this only when a complete obex packet have been received.
+         * (This is not optimal, but the current design is not really suited to
+         * the way SRM is specified.)
+         * The BT usage of SRM is not really safe - it assumes that the SRMP will fit
+         * into every OBEX packet, hence if another header occupies the entire packet,
+         * the scheme will not work - unlikely though.
+         */
+        if(mSrmEnabled) {
+            mSrmWaitingForRemote = false;
+            Byte srmp = (Byte)mReplyHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+            if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
+                mSrmWaitingForRemote = true;
+                // Clear the wait header, as the absence of the header in the next packet
+                // indicates don't wait anymore.
+                mReplyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
+            }
+        }
+        if((mSrmWaitingForRemote == false) && (mSrmEnabled == true)) {
+            mSrmActive = true;
+        }
+    }
+
     /**
      * This method starts the processing thread results. It will send the
      * initial request. If the response takes more then one packet, a thread
@@ -564,40 +632,35 @@
 
         if (mGetOperation) {
             if (!mOperationDone) {
-                if (!mGetFinalFlag) {
-                    mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
-                    while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
-                        more = sendRequest(0x03);
-                    }
-
-                    if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
-                        mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
-                    }
-                    if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
-                        mOperationDone = true;
-                    }
-                } else {
-                    more = sendRequest(0x83);
-
-                    if (more) {
-                        throw new IOException("FINAL_GET forced but data did not fit into single packet!");
-                    }
-
+                mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+                while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
+                }
+                // For GET we need to loop until all headers have been sent,
+                // And then we wait for the first continue package with the
+                // reply.
+                if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+                    mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
+                            null, mReplyHeader, mPrivateInput, mSrmActive);
+                }
+                if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
                     mOperationDone = true;
+                } else {
+                    checkForSrm();
                 }
             }
         } else {
-
+            // PUT operation
             if (!mOperationDone) {
                 mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
-                    more = sendRequest(0x02);
-
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_PUT);
                 }
             }
 
             if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
-                mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
+                mParent.sendRequest(ObexHelper.OBEX_OPCODE_PUT_FINAL,
+                        null, mReplyHeader, mPrivateInput, mSrmActive);
             }
 
             if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
@@ -617,15 +680,21 @@
     public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
             throws IOException {
 
+        // One path to the first put operation - the other one does not need to
+        // handle SRM, as all will fit into one packet.
+
         if (mGetOperation) {
             if ((inStream) && (!mOperationDone)) {
                 // to deal with inputstream in get operation
-                mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+                mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL,
+                        null, mReplyHeader, mPrivateInput, mSrmActive);
                 /*
                   * Determine if that was not the last packet in the operation
                   */
                 if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
                     mOperationDone = true;
+                } else {
+                    checkForSrm();
                 }
 
                 return true;
@@ -636,16 +705,7 @@
                 if (mPrivateInput == null) {
                     mPrivateInput = new PrivateInputStream(this);
                 }
-
-                if (!mGetFinalFlag) {
-                    sendRequest(0x03);
-                } else {
-                    sendRequest(0x83);
-
-                    if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
-                        mOperationDone = true;
-                    }
-                }
+                sendRequest(ObexHelper.OBEX_OPCODE_GET);
                 return true;
 
             } else if (mOperationDone) {
@@ -653,12 +713,13 @@
             }
 
         } else {
+            // PUT operation
             if ((!inStream) && (!mOperationDone)) {
                 // to deal with outputstream in put operation
                 if (mReplyHeader.responseCode == -1) {
                     mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
                 }
-                sendRequest(0x02);
+                sendRequest(ObexHelper.OBEX_OPCODE_PUT);
                 return true;
             } else if ((inStream) && (!mOperationDone)) {
                 // How to deal with inputstream  in put operation ?
@@ -696,7 +757,7 @@
                 }
 
                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
-                    more = sendRequest(0x02);
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_PUT);
                 }
 
                 /*
@@ -706,7 +767,7 @@
                  */
                 while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
 
-                    sendRequest(0x82);
+                    sendRequest(ObexHelper.OBEX_OPCODE_PUT_FINAL);
                 }
                 mOperationDone = true;
             } else if ((inStream) && (mOperationDone)) {
@@ -724,12 +785,14 @@
                 }
 
                 while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
-                    if (!sendRequest(0x83)) {
+                    if (!sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL)) {
                         break;
                     }
                 }
                 while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
-                    mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+                    mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL, null,
+                            mReplyHeader, mPrivateInput, false);
+                    // Regardless of the SRM state, wait for the response.
                 }
                 mOperationDone = true;
             } else if ((!inStream) && (!mOperationDone)) {
@@ -752,9 +815,9 @@
 
                 mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
-                    more = sendRequest(0x03);
+                    more = sendRequest(ObexHelper.OBEX_OPCODE_GET);
                 }
-                sendRequest(0x83);
+                sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL);
                 //                parent.sendRequest(0x83, null, replyHeaders, privateInput);
                 if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
                     mOperationDone = true;
@@ -764,5 +827,6 @@
     }
 
     public void noBodyHeader(){
+        mSendBodyHeader = false;
     }
 }
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
index 27d8976..272a920 100644
--- a/obex/javax/obex/ClientSession.java
+++ b/obex/javax/obex/ClientSession.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (c) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -37,12 +39,16 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import android.util.Log;
+
 /**
  * This class in an implementation of the OBEX ClientSession.
  * @hide
  */
 public final class ClientSession extends ObexSession {
 
+    private static final String TAG = "ClientSession";
+
     private boolean mOpen;
 
     // Determines if an OBEX layer connection has been established
@@ -51,10 +57,10 @@
     private byte[] mConnectionId = null;
 
     /*
-     * The max Packet size must be at least 256 according to the OBEX
+     * The max Packet size must be at least 255 according to the OBEX
      * specification.
      */
-    private int maxPacketSize = 256;
+    private int mMaxTxPacketSize = ObexHelper.LOWER_LIMIT_MAX_PACKET_SIZE;
 
     private boolean mRequestActive;
 
@@ -62,11 +68,33 @@
 
     private final OutputStream mOutput;
 
+    private final boolean mLocalSrmSupported;
+
+    private final ObexTransport mTransport;
+
     public ClientSession(final ObexTransport trans) throws IOException {
         mInput = trans.openInputStream();
         mOutput = trans.openOutputStream();
         mOpen = true;
         mRequestActive = false;
+        mLocalSrmSupported = trans.isSrmSupported();
+        mTransport = trans;
+    }
+
+    /**
+     * Create a ClientSession
+     * @param trans The transport to use for OBEX transactions
+     * @param supportsSrm True if Single Response Mode should be used e.g. if the
+     *        supplied transport is a TCP or l2cap channel.
+     * @throws IOException if it occurs while opening the transport streams.
+     */
+    public ClientSession(final ObexTransport trans, final boolean supportsSrm) throws IOException {
+        mInput = trans.openInputStream();
+        mOutput = trans.openOutputStream();
+        mOpen = true;
+        mRequestActive = false;
+        mLocalSrmSupported = supportsSrm;
+        mTransport = trans;
     }
 
     public HeaderSet connect(final HeaderSet header) throws IOException {
@@ -98,23 +126,25 @@
         * Byte 7 to n: headers
         */
         byte[] requestPacket = new byte[totalLength];
+        int maxRxPacketSize = ObexHelper.getMaxRxPacketSize(mTransport);
         // We just need to start at  byte 3 since the sendRequest() method will
         // handle the length and 0x80.
         requestPacket[0] = (byte)0x10;
         requestPacket[1] = (byte)0x00;
-        requestPacket[2] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
-        requestPacket[3] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
+        requestPacket[2] = (byte)(maxRxPacketSize >> 8);
+        requestPacket[3] = (byte)(maxRxPacketSize & 0xFF);
         if (head != null) {
             System.arraycopy(head, 0, requestPacket, 4, head.length);
         }
 
-        // check with local max packet size
+        // Since we are not yet connected, the peer max packet size is unknown,
+        // hence we are only guaranteed the server will use the first 7 bytes.
         if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
-            throw new IOException("Packet size exceeds max packet size");
+            throw new IOException("Packet size exceeds max packet size for connect");
         }
 
         HeaderSet returnHeaderSet = new HeaderSet();
-        sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null);
+        sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null, false);
 
         /*
         * Read the response from the OBEX server.
@@ -158,7 +188,18 @@
             System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
         }
 
-        return new ClientOperation(maxPacketSize, this, head, true);
+        if(mLocalSrmSupported) {
+            head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE);
+            /* TODO: Consider creating an interface to get the wait state.
+             * On an android system, I cannot see when this is to be used.
+             * except perhaps if we are to wait for user accept on a push message.
+            if(getLocalWaitState()) {
+                head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT);
+            }
+            */
+        }
+
+        return new ClientOperation(mMaxTxPacketSize, this, head, true);
     }
 
     /**
@@ -202,7 +243,7 @@
             }
             head = ObexHelper.createHeader(header, false);
 
-            if ((head.length + 3) > maxPacketSize) {
+            if ((head.length + 3) > mMaxTxPacketSize) {
                 throw new IOException("Packet size exceeds max packet size");
             }
         } else {
@@ -215,7 +256,7 @@
         }
 
         HeaderSet returnHeaderSet = new HeaderSet();
-        sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null);
+        sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null, false);
 
         /*
          * An OBEX DISCONNECT reply from the server:
@@ -269,7 +310,16 @@
             System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
         }
 
-        return new ClientOperation(maxPacketSize, this, head, false);
+        if(mLocalSrmSupported) {
+            head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE);
+            /* TODO: Consider creating an interface to get the wait state.
+             * On an android system, I cannot see when this is to be used.
+            if(getLocalWaitState()) {
+                head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT);
+            }
+             */
+        }
+        return new ClientOperation(mMaxTxPacketSize, this, head, false);
     }
 
     public void setAuthenticator(Authenticator auth) throws IOException {
@@ -314,7 +364,7 @@
         head = ObexHelper.createHeader(headset, false);
         totalLength += head.length;
 
-        if (totalLength > maxPacketSize) {
+        if (totalLength > mMaxTxPacketSize) {
             throw new IOException("Packet size exceeds max packet size");
         }
 
@@ -348,7 +398,7 @@
         }
 
         HeaderSet returnHeaderSet = new HeaderSet();
-        sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null);
+        sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null, false);
 
         /*
          * An OBEX SETPATH reply from the server:
@@ -400,20 +450,40 @@
      * @param head the headers to send to the client
      * @param header the header object to update with the response
      * @param privateInput the input stream used by the Operation object; null
-     *        if this is called on a CONNECT, SETPATH or DISCONNECT return
+     *        if this is called on a CONNECT, SETPATH or DISCONNECT
+     * @return
      *        <code>true</code> if the operation completed successfully;
      *        <code>false</code> if an authentication response failed to pass
      * @throws IOException if an IO error occurs
      */
     public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
-            PrivateInputStream privateInput) throws IOException {
+            PrivateInputStream privateInput, boolean srmActive) throws IOException {
         //check header length with local max size
         if (head != null) {
             if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+                // TODO: This is an implementation limit - not a specification requirement.
                 throw new IOException("header too large ");
             }
         }
 
+        boolean skipSend = false;
+        boolean skipReceive = false;
+        if (srmActive == true) {
+            if (opCode == ObexHelper.OBEX_OPCODE_PUT) {
+                // we are in the middle of a SRM PUT operation, don't expect a continue.
+                skipReceive = true;
+            } else if (opCode == ObexHelper.OBEX_OPCODE_GET) {
+                // We are still sending the get request, send, but don't expect continue
+                // until the request is transfered (the final bit is set)
+                skipReceive = true;
+            } else if (opCode == ObexHelper.OBEX_OPCODE_GET_FINAL) {
+                // All done sending the request, expect data from the server, without
+                // sending continue.
+                skipSend = true;
+            }
+
+        }
+
         int bytesReceived;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         out.write((byte)opCode);
@@ -428,86 +498,105 @@
             out.write(head);
         }
 
-        // Write the request to the output stream and flush the stream
-        mOutput.write(out.toByteArray());
-        mOutput.flush();
-
-        header.responseCode = mInput.read();
-
-        int length = ((mInput.read() << 8) | (mInput.read()));
-
-        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
-            throw new IOException("Packet received exceeds packet size limit");
+        if (!skipSend) {
+            // Write the request to the output stream and flush the stream
+            mOutput.write(out.toByteArray());
+            // TODO: is this really needed? if this flush is implemented
+            //       correctly, we will get a gap between each obex packet.
+            //       which is kind of the idea behind SRM to avoid.
+            //  Consider offloading to another thread (async action)
+            mOutput.flush();
         }
-        if (length > ObexHelper.BASE_PACKET_LENGTH) {
-            byte[] data = null;
-            if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
-                @SuppressWarnings("unused")
-                int version = mInput.read();
-                @SuppressWarnings("unused")
-                int flags = mInput.read();
-                maxPacketSize = (mInput.read() << 8) + mInput.read();
 
-                //check with local max size
-                if (maxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) {
-                    maxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE;
-                }
+        if (!skipReceive) {
+            header.responseCode = mInput.read();
 
-                if (length > 7) {
-                    data = new byte[length - 7];
+            int length = ((mInput.read() << 8) | (mInput.read()));
 
-                    bytesReceived = mInput.read(data);
-                    while (bytesReceived != (length - 7)) {
-                        bytesReceived += mInput.read(data, bytesReceived, data.length
-                                - bytesReceived);
+            if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
+                throw new IOException("Packet received exceeds packet size limit");
+            }
+            if (length > ObexHelper.BASE_PACKET_LENGTH) {
+                byte[] data = null;
+                if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
+                    @SuppressWarnings("unused")
+                    int version = mInput.read();
+                    @SuppressWarnings("unused")
+                    int flags = mInput.read();
+                    mMaxTxPacketSize = (mInput.read() << 8) + mInput.read();
+
+                    //check with local max size
+                    if (mMaxTxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) {
+                        mMaxTxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE;
+                    }
+
+                    // check with transport maximum size
+                    if(mMaxTxPacketSize > ObexHelper.getMaxTxPacketSize(mTransport)) {
+                        // To increase this size, increase the buffer size in L2CAP layer
+                        // in Bluedroid.
+                        Log.w(TAG, "An OBEX packet size of " + mMaxTxPacketSize + "was"
+                                + " requested. Transport only allows: "
+                                + ObexHelper.getMaxTxPacketSize(mTransport)
+                                + " Lowering limit to this value.");
+                        mMaxTxPacketSize = ObexHelper.getMaxTxPacketSize(mTransport);
+                    }
+
+                    if (length > 7) {
+                        data = new byte[length - 7];
+
+                        bytesReceived = mInput.read(data);
+                        while (bytesReceived != (length - 7)) {
+                            bytesReceived += mInput.read(data, bytesReceived, data.length
+                                    - bytesReceived);
+                        }
+                    } else {
+                        return true;
                     }
                 } else {
-                    return true;
+                    data = new byte[length - 3];
+                    bytesReceived = mInput.read(data);
+
+                    while (bytesReceived != (length - 3)) {
+                        bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
+                    }
+                    if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
+                        return true;
+                    }
                 }
-            } else {
-                data = new byte[length - 3];
-                bytesReceived = mInput.read(data);
 
-                while (bytesReceived != (length - 3)) {
-                    bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
+                byte[] body = ObexHelper.updateHeaderSet(header, data);
+                if ((privateInput != null) && (body != null)) {
+                    privateInput.writeBytes(body, 1);
                 }
-                if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
-                    return true;
+
+                if (header.mConnectionID != null) {
+                    mConnectionId = new byte[4];
+                    System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
                 }
-            }
 
-            byte[] body = ObexHelper.updateHeaderSet(header, data);
-            if ((privateInput != null) && (body != null)) {
-                privateInput.writeBytes(body, 1);
-            }
-
-            if (header.mConnectionID != null) {
-                mConnectionId = new byte[4];
-                System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
-            }
-
-            if (header.mAuthResp != null) {
-                if (!handleAuthResp(header.mAuthResp)) {
-                    setRequestInactive();
-                    throw new IOException("Authentication Failed");
+                if (header.mAuthResp != null) {
+                    if (!handleAuthResp(header.mAuthResp)) {
+                        setRequestInactive();
+                        throw new IOException("Authentication Failed");
+                    }
                 }
-            }
 
-            if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
-                    && (header.mAuthChall != null)) {
+                if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
+                        && (header.mAuthChall != null)) {
 
-                if (handleAuthChall(header)) {
-                    out.write((byte)HeaderSet.AUTH_RESPONSE);
-                    out.write((byte)((header.mAuthResp.length + 3) >> 8));
-                    out.write((byte)(header.mAuthResp.length + 3));
-                    out.write(header.mAuthResp);
-                    header.mAuthChall = null;
-                    header.mAuthResp = null;
+                    if (handleAuthChall(header)) {
+                        out.write((byte)HeaderSet.AUTH_RESPONSE);
+                        out.write((byte)((header.mAuthResp.length + 3) >> 8));
+                        out.write((byte)(header.mAuthResp.length + 3));
+                        out.write(header.mAuthResp);
+                        header.mAuthChall = null;
+                        header.mAuthResp = null;
 
-                    byte[] sendHeaders = new byte[out.size() - 3];
-                    System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
+                        byte[] sendHeaders = new byte[out.size() - 3];
+                        System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
 
-                    return sendRequest(opCode, sendHeaders, header, privateInput);
+                        return sendRequest(opCode, sendHeaders, header, privateInput, false);
+                    }
                 }
             }
         }
@@ -520,4 +609,8 @@
         mInput.close();
         mOutput.close();
     }
+
+    public boolean isSrmSupported() {
+        return mLocalSrmSupported;
+    }
 }
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
index 51b560a..35fe186 100644
--- a/obex/javax/obex/HeaderSet.java
+++ b/obex/javax/obex/HeaderSet.java
@@ -40,7 +40,7 @@
 
 /**
  * This class implements the javax.obex.HeaderSet interface for OBEX over
- * RFCOMM.
+ * RFCOMM or OBEX over l2cap.
  * @hide
  */
 public final class HeaderSet {
@@ -178,6 +178,22 @@
      */
     public static final int OBJECT_CLASS = 0x4F;
 
+    /**
+     * Represents the OBEX Single Response Mode (SRM). This header is used
+     * for Single response mode, introduced in OBEX 1.5.
+     * <P>
+     * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151).
+     */
+    public static final int SINGLE_RESPONSE_MODE = 0x97;
+
+    /**
+     * Represents the OBEX Single Response Mode Parameters. This header is used
+     * for Single response mode, introduced in OBEX 1.5.
+     * <P>
+     * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152).
+     */
+    public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98;
+
     private Long mCount; // 4 byte unsigned integer
 
     private String mName; // null terminated Unicode text string
@@ -204,7 +220,7 @@
 
     private byte[] mObjectClass; // byte sequence
 
-    private String[] mUnicodeUserDefined; //null terminated unicode string
+    private String[] mUnicodeUserDefined; // null terminated unicode string
 
     private byte[][] mSequenceUserDefined; // byte sequence user defined
 
@@ -212,7 +228,12 @@
 
     private Long[] mIntegerUserDefined; // 4 byte unsigned integer
 
-    private final SecureRandom mRandom;
+    private SecureRandom mRandom = null;
+
+    private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM
+
+    private Byte mSrmParam; // byte representing the SRM parameters - only "wait"
+                            // is supported by Bluetooth
 
     /*package*/ byte[] nonce;
 
@@ -234,7 +255,6 @@
         mByteUserDefined = new Byte[16];
         mIntegerUserDefined = new Long[16];
         responseCode = -1;
-        mRandom = new SecureRandom();
     }
 
     /**
@@ -393,6 +413,30 @@
                     }
                 }
                 break;
+            case SINGLE_RESPONSE_MODE:
+                if (headerValue == null) {
+                    mSingleResponseMode = null;
+                } else {
+                    if (!(headerValue instanceof Byte)) {
+                        throw new IllegalArgumentException(
+                                "Single Response Mode must be a Byte");
+                    } else {
+                        mSingleResponseMode = (Byte)headerValue;
+                    }
+                }
+                break;
+            case SINGLE_RESPONSE_MODE_PARAMETER:
+                if (headerValue == null) {
+                    mSrmParam = null;
+                } else {
+                    if (!(headerValue instanceof Byte)) {
+                        throw new IllegalArgumentException(
+                                "Single Response Mode Parameter must be a Byte");
+                    } else {
+                        mSrmParam = (Byte)headerValue;
+                    }
+                }
+                break;
             default:
                 // Verify that it was not a Unicode String user Defined
                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
@@ -493,6 +537,10 @@
                 return mObjectClass;
             case APPLICATION_PARAMETER:
                 return mAppParam;
+            case SINGLE_RESPONSE_MODE:
+                return mSingleResponseMode;
+            case SINGLE_RESPONSE_MODE_PARAMETER:
+                return mSrmParam;
             default:
                 // Verify that it was not a Unicode String user Defined
                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
@@ -564,6 +612,12 @@
         if (mObjectClass != null) {
             out.write(OBJECT_CLASS);
         }
+        if(mSingleResponseMode != null) {
+            out.write(SINGLE_RESPONSE_MODE);
+        }
+        if(mSrmParam != null) {
+            out.write(SINGLE_RESPONSE_MODE_PARAMETER);
+        }
 
         for (int i = 0x30; i < 0x40; i++) {
             if (mUnicodeUserDefined[i - 0x30] != null) {
@@ -625,6 +679,9 @@
             throws IOException {
 
         nonce = new byte[16];
+        if(mRandom == null) {
+            mRandom = new SecureRandom();
+        }
         for (int i = 0; i < 16; i++) {
             nonce[i] = (byte)mRandom.nextInt();
         }
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 0a06709..fa50943 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -42,12 +43,16 @@
 import java.util.Date;
 import java.util.TimeZone;
 
+import android.util.Log;
+
 /**
  * This class defines a set of helper methods for the implementation of Obex.
  * @hide
  */
 public final class ObexHelper {
 
+    private static final String TAG = "ObexHelper";
+    public static final boolean VDBG = false;
     /**
      * Defines the basic packet length used by OBEX. Every OBEX packet has the
      * same basic format:<BR>
@@ -65,18 +70,24 @@
      * should be the Max incoming MTU minus TODO: L2CAP package headers and
      * RFCOMM package headers. TODO: Retrieve the max incoming MTU from TODO:
      * LocalDevice.getProperty().
+     * NOTE: This value must be larger than or equal to the L2CAP SDU
      */
     /*
      * android note set as 0xFFFE to match remote MPS
      */
     public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
 
+    // The minimum allowed max packet size is 255 according to the OBEX specification
+    public static final int LOWER_LIMIT_MAX_PACKET_SIZE = 255;
+
     /**
      * Temporary workaround to be able to push files to Windows 7.
      * TODO: Should be removed as soon as Microsoft updates their driver.
      */
     public static final int MAX_CLIENT_PACKET_SIZE = 0xFC00;
 
+    public static final int OBEX_OPCODE_FINAL_BIT_MASK = 0x80;
+
     public static final int OBEX_OPCODE_CONNECT = 0x80;
 
     public static final int OBEX_OPCODE_DISCONNECT = 0x81;
@@ -119,6 +130,12 @@
 
     public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
 
+    public static final byte OBEX_SRM_ENABLE         = 0x01; // For BT we only need enable/disable
+    public static final byte OBEX_SRM_DISABLE        = 0x00;
+    public static final byte OBEX_SRM_SUPPORT        = 0x02; // Unused for now
+
+    public static final byte OBEX_SRMP_WAIT          = 0x01; // Only SRMP value used by BT
+
     /**
      * Updates the HeaderSet with the headers received in the byte array
      * provided. Invalid headers are ignored.
@@ -314,7 +331,7 @@
                             }
                         } catch (Exception e) {
                             // Not a valid header so ignore
-                            throw new IOException("Header was not formatted properly");
+                            throw new IOException("Header was not formatted properly", e);
                         }
                         index += 4;
                         break;
@@ -322,7 +339,7 @@
 
             }
         } catch (IOException e) {
-            throw new IOException("Header was not formatted properly");
+            throw new IOException("Header was not formatted properly", e);
         }
 
         return body;
@@ -672,6 +689,33 @@
                 }
             }
 
+            // TODO:
+            // If the SRM and SRMP header is in use, they must be send in the same OBEX packet
+            // But the current structure of the obex code cannot handle this, and therefore
+            // it makes sense to put them in the tail of the headers, since we then reduce the
+            // chance of enabling SRM to soon. The down side is that SRM cannot be used while
+            // transferring non-body headers
+
+            // Add the SRM header
+            byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
+            if (byteHeader != null) {
+                out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE);
+                out.write(byteHeader.byteValue());
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, null);
+                }
+            }
+
+            // Add the SRM parameter header
+            byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+            if (byteHeader != null) {
+                out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+                out.write(byteHeader.byteValue());
+                if (nullOut) {
+                    headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
+                }
+            }
+
         } catch (IOException e) {
         } finally {
             result = out.toByteArray();
@@ -702,6 +746,8 @@
         int index = start;
         int length = 0;
 
+        // TODO: Ensure SRM and SRMP headers are not split into two OBEX packets
+
         while ((fullLength < maxSize) && (index < headerArray.length)) {
             int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
             lastLength = fullLength;
@@ -1008,4 +1054,39 @@
 
         return authChall;
     }
+
+    /**
+     * Return the maximum allowed OBEX packet to transmit.
+     * OBEX packets transmitted must be smaller than this value.
+     * @param transport Reference to the ObexTransport in use.
+     * @return the maximum allowed OBEX packet to transmit
+     */
+    public static int getMaxTxPacketSize(ObexTransport transport) {
+        int size = transport.getMaxTransmitPacketSize();
+        return validateMaxPacketSize(size);
+    }
+
+    /**
+     * Return the maximum allowed OBEX packet to receive - used in OBEX connect.
+     * @param transport
+     * @return he maximum allowed OBEX packet to receive
+     */
+    public static int getMaxRxPacketSize(ObexTransport transport) {
+        int size = transport.getMaxReceivePacketSize();
+        return validateMaxPacketSize(size);
+    }
+
+    private static int validateMaxPacketSize(int size) {
+        if(VDBG && (size > MAX_PACKET_SIZE_INT)) Log.w(TAG,
+                "The packet size supported for the connection (" + size + ") is larger"
+                + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT);
+        if(size != -1) {
+            if(size < LOWER_LIMIT_MAX_PACKET_SIZE) {
+                throw new IllegalArgumentException(size + " is less that the lower limit: "
+                        + LOWER_LIMIT_MAX_PACKET_SIZE);
+            }
+            return size;
+        }
+        return MAX_PACKET_SIZE_INT;
+    }
 }
diff --git a/obex/javax/obex/ObexPacket.java b/obex/javax/obex/ObexPacket.java
new file mode 100644
index 0000000..bb6c96e
--- /dev/null
+++ b/obex/javax/obex/ObexPacket.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 The Android Open Source Project
+ * Copyright (c) 2015 Samsung LSI
+ *
+ * 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 javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ObexPacket {
+    public int mHeaderId;
+    public int mLength;
+    public byte[] mPayload = null;
+
+    private ObexPacket(int headerId, int length) {
+        mHeaderId = headerId;
+        mLength = length;
+    }
+
+    /**
+     * Create a complete OBEX packet by reading data from an InputStream.
+     * @param is the input stream to read from.
+     * @return the OBEX packet read.
+     * @throws IOException if an IO exception occurs during read.
+     */
+    public static ObexPacket read(InputStream is) throws IOException {
+        int headerId = is.read();
+        return read(headerId, is);
+    }
+
+    /**
+     * Read the remainder of an OBEX packet, with a specified headerId.
+     * @param headerId the headerId already read from the stream.
+     * @param is the stream to read from, assuming 1 byte have already been read.
+     * @return the OBEX packet read.
+     * @throws IOException
+     */
+    public static ObexPacket read(int headerId, InputStream is) throws IOException {
+        // Read the 2 byte length field from the stream
+        int length = is.read();
+        length = (length << 8) + is.read();
+
+        ObexPacket newPacket = new ObexPacket(headerId, length);
+
+        int bytesReceived;
+        byte[] temp = null;
+        if (length > 3) {
+            // First three bytes already read, compensating for this
+            temp = new byte[length - 3];
+            bytesReceived = is.read(temp);
+            while (bytesReceived != temp.length) {
+                bytesReceived += is.read(temp, bytesReceived, temp.length - bytesReceived);
+            }
+        }
+        newPacket.mPayload = temp;
+        return newPacket;
+    }
+}
diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java
index a7daeb5..542b9c8 100644
--- a/obex/javax/obex/ObexSession.java
+++ b/obex/javax/obex/ObexSession.java
@@ -34,6 +34,8 @@
 
 import java.io.IOException;
 
+import android.util.Log;
+
 /**
  * The <code>ObexSession</code> interface characterizes the term
  * "OBEX Connection" as defined in the IrDA Object Exchange Protocol v1.2, which
@@ -47,6 +49,9 @@
  */
 public class ObexSession {
 
+    private static final String TAG = "ObexSession";
+    private static final boolean V = ObexHelper.VDBG;
+
     protected Authenticator mAuthenticator;
 
     protected byte[] mChallengeDigest;
@@ -125,6 +130,7 @@
             result = mAuthenticator
                     .onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
         } catch (Exception e) {
+            if (V) Log.d(TAG, "Exception occured - returning false", e);
             return false;
         }
 
diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java
index 445e267..a5a75f5 100644
--- a/obex/javax/obex/ObexTransport.java
+++ b/obex/javax/obex/ObexTransport.java
@@ -73,4 +73,39 @@
 
     DataOutputStream openDataOutputStream() throws IOException;
 
+    /**
+     * Must return the maximum allowed OBEX packet that can be sent over
+     * the transport. For L2CAP this will be the Max SDU reported by the
+     * peer device.
+     * The returned value will be used to set the outgoing OBEX packet
+     * size. Therefore this value shall not change.
+     * For RFCOMM or other transport types where the OBEX packets size
+     * is unrelated to the transport packet size, return -1;
+     * @return the maximum allowed OBEX packet that can be send over
+     *         the transport. Or -1 in case of don't care.
+     */
+    int getMaxTransmitPacketSize();
+
+    /**
+     * Must return the maximum allowed OBEX packet that can be received over
+     * the transport. For L2CAP this will be the Max SDU configured for the
+     * L2CAP channel.
+     * The returned value will be used to validate the incoming packet size
+     * values.
+     * For RFCOMM or other transport types where the OBEX packets size
+     * is unrelated to the transport packet size, return -1;
+     * @return the maximum allowed OBEX packet that can be send over
+     *         the transport. Or -1 in case of don't care.
+     */
+    int getMaxReceivePacketSize();
+
+    /**
+     * Shall return true if the transport in use supports SRM.
+     * @return
+     *        <code>true</code> if SRM operation is supported, and is to be enabled.
+     *        <code>false</code> if SRM operations are not supported, or should not be used.
+     */
+    boolean isSrmSupported();
+
+
 }
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index fc441e0..56a675a 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -1,4 +1,5 @@
-/*
+/* Copyright (c) 2015 The Android Open Source Project
+ * Copyright (C) 2015 Samsung LSI
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -39,6 +40,8 @@
 import java.io.DataOutputStream;
 import java.io.ByteArrayOutputStream;
 
+import android.util.Log;
+
 /**
  * This class implements the Operation interface for server side connections.
  * <P>
@@ -54,6 +57,10 @@
  */
 public final class ServerOperation implements Operation, BaseStream {
 
+    private static final String TAG = "ServerOperation";
+
+    private static final boolean V = ObexHelper.VDBG; // Verbose debugging
+
     public boolean isAborted;
 
     public HeaderSet requestHeader;
@@ -78,6 +85,8 @@
 
     private PrivateOutputStream mPrivateOutput;
 
+    private ObexTransport mTransport;
+
     private boolean mPrivateOutputOpen;
 
     private String mExceptionString;
@@ -89,6 +98,19 @@
     private boolean mHasBody;
 
     private boolean mSendBodyHeader = true;
+    // Assume SRM disabled - needs to be explicit
+    // enabled by client
+    private boolean mSrmEnabled = false;
+    // A latch - when triggered, there is not way back ;-)
+    private boolean mSrmActive = false;
+    // Set to true when a SRM enable response have been send
+    private boolean mSrmResponseSent = false;
+    // keep waiting until final-bit is received in request
+    // to handle the case where the SRM enable header is in
+    // a different OBEX packet than the SRMP header.
+    private boolean mSrmWaitingForRemote = true;
+    // Why should we wait? - currently not exposed to apps.
+    private boolean mSrmLocalWait = false;
 
     /**
      * Creates new ServerOperation
@@ -116,12 +138,14 @@
         mRequestFinished = false;
         mPrivateOutputOpen = false;
         mHasBody = false;
-        int bytesReceived;
+        ObexPacket packet;
+        mTransport = p.getTransport();
 
         /*
          * Determine if this is a PUT request
          */
-        if ((request == 0x02) || (request == 0x82)) {
+        if ((request == ObexHelper.OBEX_OPCODE_PUT) ||
+                (request == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
             /*
              * It is a PUT request.
              */
@@ -130,13 +154,14 @@
             /*
              * Determine if the final bit is set
              */
-            if ((request & 0x80) == 0) {
+            if ((request & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
                 finalBitSet = false;
             } else {
                 finalBitSet = true;
                 mRequestFinished = true;
             }
-        } else if ((request == 0x03) || (request == 0x83)) {
+        } else if ((request == ObexHelper.OBEX_OPCODE_GET) ||
+                (request == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
             /*
              * It is a GET request.
              */
@@ -145,71 +170,32 @@
             // For Get request, final bit set is decided by server side logic
             finalBitSet = false;
 
-            if (request == 0x83) {
+            if (request == ObexHelper.OBEX_OPCODE_GET_FINAL) {
                 mRequestFinished = true;
             }
         } else {
             throw new IOException("ServerOperation can not handle such request");
         }
 
-        int length = in.read();
-        length = (length << 8) + in.read();
+        packet = ObexPacket.read(request, mInput);
 
         /*
          * Determine if the packet length is larger than this device can receive
          */
-        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+        if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
             mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
-            throw new IOException("Packet received was too large");
+            throw new IOException("Packet received was too large. Length: "
+                    + packet.mLength + " maxLength: " + ObexHelper.getMaxRxPacketSize(mTransport));
         }
 
         /*
          * Determine if any headers were sent in the initial request
          */
-        if (length > 3) {
-            byte[] data = new byte[length - 3];
-            bytesReceived = in.read(data);
-
-            while (bytesReceived != data.length) {
-                bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived);
+        if (packet.mLength > 3) {
+            if(!handleObexPacket(packet)) {
+                return;
             }
-
-            byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
-
-            if (body != null) {
-                mHasBody = true;
-            }
-
-            if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
-                mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
-            } else {
-                mListener.setConnectionId(1);
-            }
-
-            if (requestHeader.mAuthResp != null) {
-                if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
-                    mExceptionString = "Authentication Failed";
-                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
-                    mClosed = true;
-                    requestHeader.mAuthResp = null;
-                    return;
-                }
-            }
-
-            if (requestHeader.mAuthChall != null) {
-                mParent.handleAuthChall(requestHeader);
-                // send the  authResp to the client
-                replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
-                System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
-                        replyHeader.mAuthResp.length);
-                requestHeader.mAuthResp = null;
-                requestHeader.mAuthChall = null;
-
-            }
-
-            if (body != null) {
-                mPrivateInput.writeBytes(body, 1);
-            } else {
+            if (!mHasBody) {
                 while ((!mGetOperation) && (!finalBitSet)) {
                     sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
                     if (mPrivateInput.available() > 0) {
@@ -232,6 +218,100 @@
         }
     }
 
+    /**
+     * Parse headers and update member variables
+     * @param packet the received obex packet
+     * @return false for failing authentication - and a OBEX_HTTP_UNAUTHORIZED
+     * response have been send. Else true.
+     * @throws IOException
+     */
+    private boolean handleObexPacket(ObexPacket packet) throws IOException {
+        byte[] body = updateRequestHeaders(packet);
+
+        if (body != null) {
+            mHasBody = true;
+        }
+        if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
+            mListener.setConnectionId(ObexHelper
+                    .convertToLong(requestHeader.mConnectionID));
+        } else {
+            mListener.setConnectionId(1);
+        }
+
+        if (requestHeader.mAuthResp != null) {
+            if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+                mExceptionString = "Authentication Failed";
+                mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+                mClosed = true;
+                requestHeader.mAuthResp = null;
+                return false;
+            }
+            requestHeader.mAuthResp = null;
+        }
+
+        if (requestHeader.mAuthChall != null) {
+            mParent.handleAuthChall(requestHeader);
+            // send the auhtResp to the client
+            replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+            System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+                    replyHeader.mAuthResp.length);
+            requestHeader.mAuthResp = null;
+            requestHeader.mAuthChall = null;
+        }
+
+        if (body != null) {
+            mPrivateInput.writeBytes(body, 1);
+        }
+        return true;
+    }
+
+    /**
+     * Update the request header set, and sniff on SRM headers to update local state.
+     * @param data the OBEX packet data
+     * @return any bytes in a body/end-of-body header returned by {@link ObexHelper.updateHeaderSet}
+     * @throws IOException
+     */
+    private byte[] updateRequestHeaders(ObexPacket packet) throws IOException {
+        byte[] body = null;
+        if (packet.mPayload != null) {
+            body = ObexHelper.updateHeaderSet(requestHeader, packet.mPayload);
+        }
+        Byte srmMode = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
+        if(mTransport.isSrmSupported() && srmMode != null
+                && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
+            mSrmEnabled = true;
+            if(V) Log.d(TAG,"SRM is now ENABLED (but not active) for this operation");
+        }
+        checkForSrmWait(packet.mHeaderId);
+        if((!mSrmWaitingForRemote) && (mSrmEnabled)) {
+            if(V) Log.d(TAG,"SRM is now ACTIVE for this operation");
+            mSrmActive = true;
+        }
+        return body;
+    }
+
+    /**
+     * Call this only when a complete request have been received.
+     * (This is not optimal, but the current design is not really suited to
+     * the way SRM is specified.)
+     */
+    private void checkForSrmWait(int headerId){
+        if (mSrmEnabled && (headerId == ObexHelper.OBEX_OPCODE_GET
+                || headerId == ObexHelper.OBEX_OPCODE_GET_FINAL
+                || headerId == ObexHelper.OBEX_OPCODE_PUT)) {
+            try {
+                mSrmWaitingForRemote = false;
+                Byte srmp = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
+                if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
+                    mSrmWaitingForRemote = true;
+                    // Clear the wait header, as the absents of the header when the final bit is set
+                    // indicates don't wait.
+                    requestHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
+                }
+            } catch (IOException e) {if(V){Log.w(TAG,"Exception while extracting header",e);}}
+        }
+    }
+
     public boolean isValidBody() {
         return mHasBody;
     }
@@ -274,17 +354,19 @@
 
     /**
      * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
-     * will wait for a response from the client before ending.
+     * will wait for a response from the client before ending unless SRM is active.
      * @param type the response code to send back to the client
      * @return <code>true</code> if the final bit was not set on the reply;
      *         <code>false</code> if no reply was received because the operation
-     *         ended, an abort was received, or the final bit was set in the
-     *         reply
+     *         ended, an abort was received, the final bit was set in the
+     *         reply or SRM is active.
      * @throws IOException if an IO error occurs
      */
     public synchronized boolean sendReply(int type) throws IOException {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        int bytesReceived;
+        boolean skipSend = false;
+        boolean skipReceive = false;
+        boolean srmRespSendPending = false;
 
         long id = mListener.getConnectionId();
         if (id == -1) {
@@ -293,7 +375,19 @@
             replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
         }
 
-        byte[] headerArray = ObexHelper.createHeader(replyHeader, true);
+        if(mSrmEnabled && !mSrmResponseSent) {
+            // As we are not ensured that the SRM enable is in the first OBEX packet
+            // We must check for each reply.
+            if(V)Log.v(TAG, "mSrmEnabled==true, sending SRM enable response.");
+            replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRM_ENABLE);
+            srmRespSendPending = true;
+        }
+
+        if(mSrmEnabled && !mGetOperation && mSrmLocalWait) {
+            replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRMP_WAIT);
+        }
+
+        byte[] headerArray = ObexHelper.createHeader(replyHeader, true); // This clears the headers
         int bodyLength = -1;
         int orginalBodyLength = -1;
 
@@ -347,6 +441,28 @@
             finalBitSet = true;
         }
 
+        if(mSrmActive) {
+            if(!mGetOperation && type == ResponseCodes.OBEX_HTTP_CONTINUE &&
+                    mSrmResponseSent == true) {
+                // we are in the middle of a SRM PUT operation, don't send a continue.
+                skipSend = true;
+            } else if(mGetOperation && mRequestFinished == false && mSrmResponseSent == true) {
+                // We are still receiving the get request, receive, but don't send continue.
+                skipSend = true;
+            } else if(mGetOperation && mRequestFinished == true) {
+                // All done receiving the GET request, send data to the client, without
+                // expecting a continue.
+                skipReceive = true;
+            }
+            if(V)Log.v(TAG, "type==" + type + " skipSend==" + skipSend
+                    + " skipReceive==" + skipReceive);
+        }
+        if(srmRespSendPending) {
+            if(V)Log.v(TAG,
+                    "SRM Enabled (srmRespSendPending == true)- sending SRM Enable response");
+            mSrmResponseSent = true;
+        }
+
         if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
             if (bodyLength > 0) {
                 /*
@@ -387,7 +503,7 @@
         }
 
         if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
-            if(mSendBodyHeader == true) {
+            if(mSendBodyHeader) {
                 out.write(0x49);
                 orginalBodyLength = 3;
                 out.write((byte)(orginalBodyLength >> 8));
@@ -395,107 +511,66 @@
             }
         }
 
-        mResponseSize = 3;
-        mParent.sendResponse(type, out.toByteArray());
+        if(skipSend == false) {
+            mResponseSize = 3;
+            mParent.sendResponse(type, out.toByteArray());
+        }
 
         if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
-            int headerID = mInput.read();
-            int length = mInput.read();
-            length = (length << 8) + mInput.read();
-            if ((headerID != ObexHelper.OBEX_OPCODE_PUT)
-                    && (headerID != ObexHelper.OBEX_OPCODE_PUT_FINAL)
-                    && (headerID != ObexHelper.OBEX_OPCODE_GET)
-                    && (headerID != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
 
-                if (length > 3) {
-                    byte[] temp = new byte[length - 3];
-                    // First three bytes already read, compensating for this
-                    bytesReceived = mInput.read(temp);
-
-                    while (bytesReceived != temp.length) {
-                        bytesReceived += mInput.read(temp, bytesReceived,
-                                temp.length - bytesReceived);
-                    }
-                }
-
-                /*
-                 * Determine if an ABORT was sent as the reply
-                 */
-                if (headerID == ObexHelper.OBEX_OPCODE_ABORT) {
-                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
-                    mClosed = true;
-                    isAborted = true;
-                    mExceptionString = "Abort Received";
-                    throw new IOException("Abort Received");
-                } else {
-                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
-                    mClosed = true;
-                    mExceptionString = "Bad Request Received";
-                    throw new IOException("Bad Request Received");
-                }
+            if(mGetOperation && skipReceive) {
+                // Here we need to check for and handle abort (throw an exception).
+                // Any other signal received should be discarded silently (only on server side)
+                checkSrmRemoteAbort();
             } else {
+                // Receive and handle data (only send reply if !skipSend)
+                // Read a complete OBEX Packet
+                ObexPacket packet = ObexPacket.read(mInput);
 
-                if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
-                    finalBitSet = true;
-                } else if (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL) {
-                    mRequestFinished = true;
-                }
+                int headerId = packet.mHeaderId;
+                if ((headerId != ObexHelper.OBEX_OPCODE_PUT)
+                        && (headerId != ObexHelper.OBEX_OPCODE_PUT_FINAL)
+                        && (headerId != ObexHelper.OBEX_OPCODE_GET)
+                        && (headerId != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
 
-                /*
-                 * Determine if the packet length is larger then this device can receive
-                 */
-                if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
-                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
-                    throw new IOException("Packet received was too large");
-                }
-
-                /*
-                 * Determine if any headers were sent in the initial request
-                 */
-                if (length > 3) {
-                    byte[] data = new byte[length - 3];
-                    bytesReceived = mInput.read(data);
-
-                    while (bytesReceived != data.length) {
-                        bytesReceived += mInput.read(data, bytesReceived, data.length
-                                - bytesReceived);
-                    }
-                    byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
-                    if (body != null) {
-                        mHasBody = true;
-                    }
-                    if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
-                        mListener.setConnectionId(ObexHelper
-                                .convertToLong(requestHeader.mConnectionID));
+                    /*
+                     * Determine if an ABORT was sent as the reply
+                     */
+                    if (headerId == ObexHelper.OBEX_OPCODE_ABORT) {
+                        handleRemoteAbort();
                     } else {
-                        mListener.setConnectionId(1);
+                        // TODO:shall we send this if it occurs during SRM? Errata on the subject
+                        mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
+                        mClosed = true;
+                        mExceptionString = "Bad Request Received";
+                        throw new IOException("Bad Request Received");
+                    }
+                } else {
+
+                    if ((headerId == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
+                        finalBitSet = true;
+                    } else if (headerId == ObexHelper.OBEX_OPCODE_GET_FINAL) {
+                        mRequestFinished = true;
                     }
 
-                    if (requestHeader.mAuthResp != null) {
-                        if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
-                            mExceptionString = "Authentication Failed";
-                            mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
-                            mClosed = true;
-                            requestHeader.mAuthResp = null;
+                    /*
+                     * Determine if the packet length is larger than the negotiated packet size
+                     */
+                    if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
+                        mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+                        throw new IOException("Packet received was too large");
+                    }
+
+                    /*
+                     * Determine if any headers were sent in the initial request
+                     */
+                    if (packet.mLength > 3 || (mSrmEnabled && packet.mLength == 3)) {
+                        if(handleObexPacket(packet) == false) {
                             return false;
                         }
-                        requestHeader.mAuthResp = null;
-                    }
-
-                    if (requestHeader.mAuthChall != null) {
-                        mParent.handleAuthChall(requestHeader);
-                        // send the auhtResp to the client
-                        replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
-                        System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
-                                replyHeader.mAuthResp.length);
-                        requestHeader.mAuthResp = null;
-                        requestHeader.mAuthChall = null;
-                    }
-
-                    if (body != null) {
-                        mPrivateInput.writeBytes(body, 1);
                     }
                 }
+
             }
             return true;
         } else {
@@ -504,6 +579,53 @@
     }
 
     /**
+     * This method will look for an abort from the peer during a SRM transfer.
+     * The function will not block if no data has been received from the remote device.
+     * If data have been received, the function will block while reading the incoming
+     * OBEX package.
+     * An Abort request will be handled, and cause an IOException("Abort Received").
+     * Other messages will be discarded silently as per GOEP specification.
+     * @throws IOException if an abort request have been received.
+     * TODO: I think this is an error in the specification. If we discard other messages,
+     *       the peer device will most likely stall, as it will not receive the expected
+     *       response for the message...
+     *       I'm not sure how to understand "Receipt of invalid or unexpected SRM or SRMP
+     *       header values shall be ignored by the receiving device."
+     *       If any signal is received during an active SRM transfer it is unexpected regardless
+     *       whether or not it contains SRM/SRMP headers...
+     */
+    private void checkSrmRemoteAbort() throws IOException {
+        if(mInput.available() > 0) {
+            ObexPacket packet = ObexPacket.read(mInput);
+            /*
+             * Determine if an ABORT was sent as the reply
+             */
+            if (packet.mHeaderId == ObexHelper.OBEX_OPCODE_ABORT) {
+                handleRemoteAbort();
+            } else {
+                // TODO: should we throw an exception here anyway? - don't see how to
+                //       ignore SRM/SRMP headers without ignoring the complete signal
+                //       (in this particular case).
+                Log.w(TAG, "Received unexpected request from client - discarding...\n"
+                        + "   headerId: " + packet.mHeaderId + " length: " + packet.mLength);
+            }
+        }
+    }
+
+    private void handleRemoteAbort() throws IOException {
+        /* TODO: To increase the speed of the abort operation in SRM, we need
+         *       to be able to flush the L2CAP queue for the PSM in use.
+         *       This could be implemented by introducing a control
+         *       message to be send over the socket, that in the abort case
+         *       could carry a flush command. */
+        mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
+        mClosed = true;
+        isAborted = true;
+        mExceptionString = "Abort Received";
+        throw new IOException("Abort Received");
+    }
+
+    /**
      * Sends an ABORT message to the server. By calling this method, the
      * corresponding input and output streams will be closed along with this
      * object.
diff --git a/obex/javax/obex/ServerRequestHandler.java b/obex/javax/obex/ServerRequestHandler.java
index 0882572..09cbc2c 100644
--- a/obex/javax/obex/ServerRequestHandler.java
+++ b/obex/javax/obex/ServerRequestHandler.java
@@ -275,4 +275,13 @@
      */
     public void onClose() {
     }
+
+    /**
+     * Override to add Single Response Mode support - e.g. if the supplied
+     * transport is l2cap.
+     * @return True if SRM is supported, else False
+     */
+    public boolean isSrmSupported() {
+        return false;
+    }
 }
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index f1b9a0d..acee5dd 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -1,4 +1,6 @@
 /*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (c) 2015 Samsung LSI
  * Copyright (c) 2008-2009, Motorola, Inc.
  *
  * All rights reserved.
@@ -45,6 +47,7 @@
 public final class ServerSession extends ObexSession implements Runnable {
 
     private static final String TAG = "Obex ServerSession";
+    private static final boolean V = ObexHelper.VDBG;
 
     private ObexTransport mTransport;
 
@@ -91,7 +94,9 @@
 
             boolean done = false;
             while (!done && !mClosed) {
+                if(V) Log.v(TAG, "Waiting for incoming request...");
                 int requestType = mInput.read();
+                if(V) Log.v(TAG, "Read request: " + requestType);
                 switch (requestType) {
                     case ObexHelper.OBEX_OPCODE_CONNECT:
                         handleConnectRequest();
@@ -140,9 +145,9 @@
             }
 
         } catch (NullPointerException e) {
-            Log.d(TAG, e.toString());
+            Log.d(TAG, "Exception occured - ignoring", e);
         } catch (Exception e) {
-            Log.d(TAG, e.toString());
+            Log.d(TAG, "Exception occured - ignoring", e);
         }
         close();
     }
@@ -163,7 +168,7 @@
 
         int length = mInput.read();
         length = (length << 8) + mInput.read();
-        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
             code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
         } else {
             for (int i = 3; i < length; i++) {
@@ -215,6 +220,7 @@
              *internal error should not be sent because server has already replied with
              *OK response in "sendReply")
              */
+            if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
             if (!op.isAborted) {
                 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
             }
@@ -243,6 +249,7 @@
                 op.sendReply(response);
             }
         } catch (Exception e) {
+            if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
             sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
         }
     }
@@ -275,7 +282,7 @@
             data[2] = (byte)totalLength;
         }
         op.write(data);
-        op.flush();
+        op.flush(); // TODO: Do we need to flush?
     }
 
     /**
@@ -304,7 +311,7 @@
         flags = mInput.read();
         constants = mInput.read();
 
-        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
             code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
             totalLength = 3;
         } else {
@@ -358,6 +365,7 @@
                 try {
                     code = mListener.onSetPath(request, reply, backup, create);
                 } catch (Exception e) {
+                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
                     sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
                     return;
                 }
@@ -425,7 +433,7 @@
         length = mInput.read();
         length = (length << 8) + mInput.read();
 
-        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
             code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
             totalLength = 3;
         } else {
@@ -466,6 +474,7 @@
                 try {
                     mListener.onDisconnect(request, reply);
                 } catch (Exception e) {
+                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
                     sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
                     return;
                 }
@@ -531,23 +540,38 @@
         HeaderSet reply = new HeaderSet();
         int bytesReceived;
 
+        if(V) Log.v(TAG,"handleConnectRequest()");
+
         /*
          * Read in the length of the OBEX packet, OBEX version, flags, and max
          * packet length
          */
         packetLength = mInput.read();
         packetLength = (packetLength << 8) + mInput.read();
+        if(V) Log.v(TAG,"handleConnectRequest() - packetLength: " + packetLength);
+
         version = mInput.read();
         flags = mInput.read();
         mMaxPacketLength = mInput.read();
         mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
 
+        if(V) Log.v(TAG,"handleConnectRequest() - version: " + version
+                + " MaxLength: " + mMaxPacketLength + " flags: " + flags);
+
         // should we check it?
         if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
             mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
         }
 
-        if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+        if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) {
+            Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength
+                    + " is larger than the max size supported by the transport: "
+                    + ObexHelper.getMaxTxPacketSize(mTransport)
+                    + " Reducing to this size.");
+            mMaxPacketLength = ObexHelper.getMaxTxPacketSize(mTransport);
+        }
+
+        if (packetLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
             code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
             totalLength = 7;
         } else {
@@ -614,7 +638,7 @@
                         code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
                     }
                 } catch (Exception e) {
-                    e.printStackTrace();
+                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
                     totalLength = 7;
                     head = null;
                     code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -633,13 +657,14 @@
          * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
          */
         byte[] sendData = new byte[totalLength];
+        int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
         sendData[0] = (byte)code;
         sendData[1] = length[2];
         sendData[2] = length[3];
         sendData[3] = (byte)0x10;
         sendData[4] = (byte)0x00;
-        sendData[5] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
-        sendData[6] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
+        sendData[5] = (byte)(maxRxLength >> 8);
+        sendData[6] = (byte)(maxRxLength & 0xFF);
 
         if (head != null) {
             System.arraycopy(head, 0, sendData, 7, head.length);
@@ -659,11 +684,16 @@
             mListener.onClose();
         }
         try {
-            mInput.close();
-            mOutput.close();
-            mTransport.close();
+            /* Set state to closed before interrupting the thread by closing the streams */
             mClosed = true;
+            if(mInput != null)
+                mInput.close();
+            if(mOutput != null)
+                mOutput.close();
+            if(mTransport != null)
+                mTransport.close();
         } catch (Exception e) {
+            if(V) Log.d(TAG,"Exception occured during close() - ignore",e);
         }
         mTransport = null;
         mInput = null;
@@ -702,4 +732,7 @@
         return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
     }
 
+    public ObexTransport getTransport() {
+        return mTransport;
+    }
 }
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index 2ec15be..aea8585 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -21,6 +21,7 @@
 
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
 
     <application android:label="@string/app_name" >
         <activity
@@ -28,9 +29,8 @@
             android:label="@string/action_bar_label"
             android:theme="@style/AppTheme" >
             <intent-filter>
-                <action android:name="android.intent.action.ACTION_SEND"/>
+                <action android:name="android.net.conn.CAPTIVE_PORTAL"/>
                 <category android:name="android.intent.category.DEFAULT"/>
-                <data android:mimeType="text/plain"/>
             </intent-filter>
         </activity>
     </application>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index d898555..81ff2ab 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -58,24 +58,13 @@
     private static final String DEFAULT_SERVER = "connectivitycheck.android.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
 
-    // Keep this in sync with NetworkMonitor.
-    // Intent broadcast to ConnectivityService indicating sign-in is complete.
-    // Extras:
-    //     EXTRA_TEXT       = netId
-    //     LOGGED_IN_RESULT = one of the CAPTIVE_PORTAL_APP_RETURN_* values below.
-    //     RESPONSE_TOKEN   = data fragment from launching Intent
-    private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN =
-            "android.net.netmon.captive_portal_logged_in";
-    private static final String LOGGED_IN_RESULT = "result";
-    private static final int CAPTIVE_PORTAL_APP_RETURN_APPEASED = 0;
-    private static final int CAPTIVE_PORTAL_APP_RETURN_UNWANTED = 1;
-    private static final int CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS = 2;
-    private static final String RESPONSE_TOKEN = "response_token";
+    private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
 
     private URL mURL;
-    private int mNetId;
+    private Network mNetwork;
     private String mResponseToken;
     private NetworkCallback mNetworkCallback;
+    private ConnectivityManager mCm;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -83,23 +72,19 @@
 
         String server = Settings.Global.getString(getContentResolver(), "captive_portal_server");
         if (server == null) server = DEFAULT_SERVER;
+        mCm = ConnectivityManager.from(this);
         try {
             mURL = new URL("http", server, "/generate_204");
-            final Uri dataUri = getIntent().getData();
-            if (!dataUri.getScheme().equals("netid")) {
-                throw new MalformedURLException();
-            }
-            mNetId = Integer.parseInt(dataUri.getSchemeSpecificPart());
-            mResponseToken = dataUri.getFragment();
-        } catch (MalformedURLException|NumberFormatException e) {
+        } catch (MalformedURLException e) {
             // System misconfigured, bail out in a way that at least provides network access.
-            done(CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS);
+            Log.e(TAG, "Invalid captive portal URL, server=" + server);
+            done(Result.WANTED_AS_IS);
         }
+        mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
+        mResponseToken = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_TOKEN);
 
-        final ConnectivityManager cm = ConnectivityManager.from(this);
-        final Network network = new Network(mNetId);
         // Also initializes proxy system properties.
-        cm.setProcessDefaultNetwork(network);
+        mCm.bindProcessToNetwork(mNetwork);
 
         // Proxy system properties must be initialized before setContentView is called because
         // setContentView initializes the WebView logic which in turn reads the system properties.
@@ -108,7 +93,7 @@
         getActionBar().setDisplayShowHomeEnabled(false);
 
         // Exit app if Network disappears.
-        final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
+        final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
         if (networkCapabilities == null) {
             finish();
             return;
@@ -116,14 +101,14 @@
         mNetworkCallback = new NetworkCallback() {
             @Override
             public void onLost(Network lostNetwork) {
-                if (network.equals(lostNetwork)) done(CAPTIVE_PORTAL_APP_RETURN_UNWANTED);
+                if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
             }
         };
         final NetworkRequest.Builder builder = new NetworkRequest.Builder();
         for (int transportType : networkCapabilities.getTransportTypes()) {
             builder.addTransportType(transportType);
         }
-        cm.registerNetworkCallback(builder.build(), mNetworkCallback);
+        mCm.registerNetworkCallback(builder.build(), mNetworkCallback);
 
         final WebView myWebView = (WebView) findViewById(R.id.webview);
         myWebView.clearCache(true);
@@ -160,15 +145,21 @@
         }
     }
 
-    private void done(int result) {
+    private void done(Result result) {
         if (mNetworkCallback != null) {
-            ConnectivityManager.from(this).unregisterNetworkCallback(mNetworkCallback);
+            mCm.unregisterNetworkCallback(mNetworkCallback);
         }
-        Intent intent = new Intent(ACTION_CAPTIVE_PORTAL_LOGGED_IN);
-        intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(mNetId));
-        intent.putExtra(LOGGED_IN_RESULT, String.valueOf(result));
-        intent.putExtra(RESPONSE_TOKEN, mResponseToken);
-        sendBroadcast(intent);
+        switch (result) {
+            case DISMISSED:
+                mCm.reportCaptivePortalDismissed(mNetwork, mResponseToken);
+                break;
+            case UNWANTED:
+                mCm.ignoreNetworkWithCaptivePortal(mNetwork, mResponseToken);
+                break;
+            case WANTED_AS_IS:
+                mCm.useNetworkWithCaptivePortal(mNetwork, mResponseToken);
+                break;
+        }
         finish();
     }
 
@@ -192,11 +183,11 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         int id = item.getItemId();
         if (id == R.id.action_use_network) {
-            done(CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS);
+            done(Result.WANTED_AS_IS);
             return true;
         }
         if (id == R.id.action_do_not_use_network) {
-            done(CAPTIVE_PORTAL_APP_RETURN_UNWANTED);
+            done(Result.UNWANTED);
             return true;
         }
         return super.onOptionsItemSelected(item);
@@ -225,7 +216,7 @@
                     if (urlConnection != null) urlConnection.disconnect();
                 }
                 if (httpResponseCode == 204) {
-                    done(CAPTIVE_PORTAL_APP_RETURN_APPEASED);
+                    done(Result.DISMISSED);
                 }
             }
         }).start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
index f2b2f66..a7fdadc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
@@ -162,7 +162,7 @@
                 usage.warningLevel = DEFAULT_WARNING_LEVEL;
             }
             if (usage != null) {
-                usage.carrier = mNetworkController.getMobileNetworkName();
+                usage.carrier = mNetworkController.getMobileDataNetworkName();
             }
             return usage;
         } catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9a7f21e..45704f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -206,7 +206,7 @@
         filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
         filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
@@ -277,9 +277,9 @@
         return mDefaultSignalController;
     }
 
-    public String getMobileNetworkName() {
+    public String getMobileDataNetworkName() {
         MobileSignalController controller = getDataController();
-        return controller != null ? controller.getState().networkName : "";
+        return controller != null ? controller.getState().networkNameData : "";
     }
 
     public boolean isEmergencyOnly() {
@@ -373,7 +373,7 @@
             Log.d(TAG, "onReceive: intent=" + intent);
         }
         final String action = intent.getAction();
-        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) ||
+        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
             updateConnectivity();
             refreshCarrierLabel();
@@ -1039,6 +1039,7 @@
             mapIconSets();
 
             mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault;
+            mLastState.networkNameData = mCurrentState.networkNameData = mNetworkNameDefault;
             mLastState.enabled = mCurrentState.enabled = hasMobileData;
             mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
             // Get initial data sim state.
@@ -1274,6 +1275,7 @@
             if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
                 updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
                         intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
+                        intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
                         intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
                         intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
                 notifyListenersIfNecessary();
@@ -1302,14 +1304,18 @@
         /**
          * Updates the network's name based on incoming spn and plmn.
          */
-        void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+        void updateNetworkName(boolean showSpn, String spn, String dataSpn,
+                boolean showPlmn, String plmn) {
             if (CHATTY) {
-                Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
+                        + " spn=" + spn + " dataSpn=" + dataSpn
                         + " showPlmn=" + showPlmn + " plmn=" + plmn);
             }
             StringBuilder str = new StringBuilder();
+            StringBuilder strData = new StringBuilder();
             if (showPlmn && plmn != null) {
                 str.append(plmn);
+                strData.append(plmn);
             }
             if (showSpn && spn != null) {
                 if (str.length() != 0) {
@@ -1322,6 +1328,17 @@
             } else {
                 mCurrentState.networkName = mNetworkNameDefault;
             }
+            if (showSpn && dataSpn != null) {
+                if (strData.length() != 0) {
+                    strData.append(mNetworkNameSeparator);
+                }
+                strData.append(dataSpn);
+            }
+            if (strData.length() != 0) {
+                mCurrentState.networkNameData = strData.toString();
+            } else {
+                mCurrentState.networkNameData = mNetworkNameDefault;
+            }
         }
 
         /**
@@ -1450,6 +1467,7 @@
 
         static class MobileState extends SignalController.State {
             String networkName;
+            String networkNameData;
             boolean dataSim;
             boolean dataConnected;
             boolean isEmergency;
@@ -1462,6 +1480,7 @@
                 MobileState state = (MobileState) s;
                 dataSim = state.dataSim;
                 networkName = state.networkName;
+                networkNameData = state.networkNameData;
                 dataConnected = state.dataConnected;
                 inetForNetwork = state.inetForNetwork;
                 isEmergency = state.isEmergency;
@@ -1474,6 +1493,7 @@
                 builder.append(',');
                 builder.append("dataSim=").append(dataSim).append(',');
                 builder.append("networkName=").append(networkName).append(',');
+                builder.append("networkNameData=").append(networkNameData).append(',');
                 builder.append("dataConnected=").append(dataConnected).append(',');
                 builder.append("inetForNetwork=").append(inetForNetwork).append(',');
                 builder.append("isEmergency=").append(isEmergency).append(',');
@@ -1484,6 +1504,7 @@
             public boolean equals(Object o) {
                 return super.equals(o)
                         && Objects.equals(((MobileState) o).networkName, networkName)
+                        && Objects.equals(((MobileState) o).networkNameData, networkNameData)
                         && ((MobileState) o).dataSim == dataSim
                         && ((MobileState) o).dataConnected == dataConnected
                         && ((MobileState) o).isEmergency == isEmergency
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 32a6a2f..46a4599 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -58,6 +58,7 @@
 import java.util.List;
 import java.util.Vector;
 
+import java.util.*;
 class BluetoothManagerService extends IBluetoothManager.Stub {
     private static final String TAG = "BluetoothManagerService";
     private static final boolean DBG = true;
@@ -114,6 +115,7 @@
     private static final int SERVICE_IBLUETOOTHGATT = 2;
 
     private final Context mContext;
+    private static int mBleAppCount = 0;
 
     // Locks are not provided for mName and mAddress.
     // They are accessed in handler or broadcast receiver, same thread context.
@@ -186,11 +188,40 @@
                             persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
                         }
                     }
+
+                    int st = BluetoothAdapter.STATE_OFF;
+                    if (mBluetooth != null) {
+                        try {
+                            st = mBluetooth.getState();
+                        } catch (RemoteException e) {
+                            Log.e(TAG,"Unable to call getState", e);
+                        }
+                    }
+                    Log.d(TAG, "state" + st);
+
                     if (isAirplaneModeOn()) {
-                        // disable without persisting the setting
-                        sendDisableMsg();
+                        // Clear registered LE apps to force shut-off
+                        synchronized (this) {
+                            mBleAppCount = 0;
+                        }
+                        if (st == BluetoothAdapter.STATE_BLE_ON) {
+                            //if state is BLE_ON make sure you trigger disableBLE part
+                            try {
+                                if (mBluetooth != null) {
+                                    mBluetooth.onBrEdrDown();
+                                    mEnableExternal = false;
+                                }
+                            } catch(RemoteException e) {
+                                Log.e(TAG,"Unable to call onBrEdrDown", e);
+                            }
+                        } else if (st == BluetoothAdapter.STATE_ON){
+                            // disable without persisting the setting
+                            Log.d(TAG, "Calling disable");
+                            sendDisableMsg();
+                        }
                     } else if (mEnableExternal) {
                         // enable without persisting the setting
+                        Log.d(TAG, "Calling enable");
                         sendEnableMsg(mQuietEnableExternal);
                     }
                 }
@@ -205,12 +236,6 @@
                         sendEnableMsg(mQuietEnableExternal);
                     }
                 }
-
-                if (!isNameAndAddressSet()) {
-                    //Sync the Bluetooth name and address from the Bluetooth Adapter
-                    if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
-                    getNameAndAddress();
-                }
             }
         }
     };
@@ -220,6 +245,7 @@
 
         mContext = context;
         mBluetooth = null;
+        mBluetoothGatt = null;
         mBinding = false;
         mUnbinding = false;
         mEnable = false;
@@ -398,6 +424,133 @@
         return false;
     }
 
+    class ClientDeathRecipient implements IBinder.DeathRecipient {
+        public void binderDied() {
+            if (DBG) Log.d(TAG, "Binder is dead -  unregister Ble App");
+            if (mBleAppCount > 0) --mBleAppCount;
+
+            if (mBleAppCount == 0) {
+                if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
+                try {
+                    if (mBluetooth != null) {
+                        mBluetooth.onBrEdrDown();
+                    }
+                } catch(RemoteException e) {
+                     Log.e(TAG,"Unable to call onBrEdrDown", e);
+                }
+            }
+        }
+    }
+
+    /** Internal death rec list */
+    Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
+
+    public int updateBleAppCount(IBinder token, boolean enable) {
+        if (enable) {
+            ClientDeathRecipient r = mBleApps.get(token);
+            if (r == null) {
+                ClientDeathRecipient deathRec = new ClientDeathRecipient();
+                try {
+                    token.linkToDeath(deathRec, 0);
+                } catch (RemoteException ex) {
+                    throw new IllegalArgumentException("Wake lock is already dead.");
+                }
+                mBleApps.put(token, deathRec);
+                synchronized (this) {
+                    ++mBleAppCount;
+                }
+                if (DBG) Log.d(TAG, "Registered for death Notification");
+            }
+
+        } else  {
+            ClientDeathRecipient r = mBleApps.get(token);
+            if (r != null) {
+                try {
+                    token.linkToDeath(r, 0);
+                } catch (RemoteException ex) {
+                    throw new IllegalArgumentException("Wake lock is already dead.");
+                }
+                mBleApps.remove(token);
+                synchronized (this) {
+                    if (mBleAppCount > 0) --mBleAppCount;
+                }
+                if (DBG) Log.d(TAG, "Unregistered for death Notification");
+            }
+        }
+        if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
+        if (mBleAppCount == 0 && mEnable) {
+            try {
+                if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
+                    if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
+                    mEnable = false;
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "getState()", e);
+            }
+        }
+        return mBleAppCount;
+    }
+
+    /** @hide*/
+    public boolean isBleAppPresent() {
+        if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
+        return (mBleAppCount > 0);
+    }
+
+    /**
+     * Action taken when GattService is turned off
+     */
+    private void onBluetoothGattServiceUp() {
+        if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
+        try{
+            if (isBleAppPresent() == false && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+                mBluetooth.onLeServiceUp();
+
+                // waive WRITE_SECURE_SETTINGS permission check
+                long callingIdentity = Binder.clearCallingIdentity();
+                persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+                Binder.restoreCallingIdentity(callingIdentity);
+            }
+        } catch(RemoteException e) {
+                Log.e(TAG,"Unable to call onServiceUp", e);
+        }
+    }
+
+    /**
+     * Inform BluetoothAdapter instances that BREDR part is down
+     * and turn off all service and stack if no LE app needs it
+     */
+    private void sendBrEdrDownCallback() {
+        if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
+        int n = mCallbacks.beginBroadcast();
+
+        if (isBleAppPresent() == false) {
+            try {
+                mBluetooth.onBrEdrDown();
+            } catch(RemoteException e) {
+                Log.e(TAG,"Unable to call onBrEdrDown", e);
+            }
+        }
+        else{//need to stay at BLE ON. disconnect all Gatt connections
+            try{
+                mBluetoothGatt.unregAll();//disconnectAll();
+            } catch(RemoteException e) {
+                Log.e(TAG,"Unable to disconn all", e);
+            }
+        }
+
+        Log.d(TAG,"Broadcasting onBrEdrDown() to " + n + " receivers.");
+        for (int i=0; i <n; i++) {
+            try {
+                mCallbacks.getBroadcastItem(i).onBrEdrDown();
+            }  catch (RemoteException e) {
+                Log.e(TAG, "Unable to call sendBrEdrDownCallback() on callback #" + i, e);
+            }
+        }
+        mCallbacks.finishBroadcast();
+    }
+
+    /** @hide*/
     public void getNameAndAddress() {
         if (DBG) {
             Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
@@ -447,11 +600,9 @@
             mQuietEnableExternal = false;
             mEnableExternal = true;
             // waive WRITE_SECURE_SETTINGS permission check
-            long callingIdentity = Binder.clearCallingIdentity();
-            persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
-            Binder.restoreCallingIdentity(callingIdentity);
             sendEnableMsg(false);
         }
+        if (DBG) Log.d(TAG, "enable returning");
         return true;
     }
 
@@ -510,6 +661,7 @@
             } else {
                 mUnbinding=false;
             }
+            mBluetoothGatt = null;
         }
     }
 
@@ -1036,6 +1188,7 @@
                     synchronized(mConnection) {
                         if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                             mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
+                            onBluetoothGattServiceUp();
                             break;
                         } // else must be SERVICE_IBLUETOOTH
 
@@ -1113,12 +1266,18 @@
                     bluetoothStateChangeHandler(prevState, newState);
                     // handle error state transition case from TURNING_ON to OFF
                     // unbind and rebind bluetooth service and enable bluetooth
-                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
+                    if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
                         (newState == BluetoothAdapter.STATE_OFF) &&
                         (mBluetooth != null) && mEnable) {
                         recoverBluetoothServiceFromError();
                     }
-                    if (newState == BluetoothAdapter.STATE_ON) {
+                    if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
+                        (newState == BluetoothAdapter.STATE_BLE_ON) &&
+                        (mBluetooth != null) && mEnable) {
+                        recoverBluetoothServiceFromError();
+                    }
+                    if (newState == BluetoothAdapter.STATE_ON ||
+                        newState == BluetoothAdapter.STATE_BLE_ON) {
                         // bluetooth is working, reset the counter
                         if (mErrorRecoveryRetryCounter != 0) {
                             Log.w(TAG, "bluetooth is recovered from error");
@@ -1378,39 +1537,90 @@
         return valid;
     }
 
+    private void sendBleStateChanged(int prevState, int newState) {
+        if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
+        // Send broadcast message to everyone else
+        Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
+        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
+        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
+    }
+
     private void bluetoothStateChangeHandler(int prevState, int newState) {
+        boolean isStandardBroadcast = true;
         if (prevState != newState) {
             //Notify all proxy objects first of adapter state change
-            if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
-                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
-                sendBluetoothStateCallback(isUp);
+            if (newState == BluetoothAdapter.STATE_BLE_ON
+                   || newState == BluetoothAdapter.STATE_OFF) {
+                boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
+                   && newState == BluetoothAdapter.STATE_BLE_ON);
 
-                if (isUp) {
-                    // connect to GattService
-                    if (mContext.getPackageManager().hasSystemFeature(
-                                                     PackageManager.FEATURE_BLUETOOTH_LE)) {
-                        Intent i = new Intent(IBluetoothGatt.class.getName());
-                        doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
-                                UserHandle.CURRENT);
-                    }
-                } else {
-                    //If Bluetooth is off, send service down event to proxy objects, and unbind
-                    if (!isUp && canUnbindBluetoothService()) {
-                        unbindAllBluetoothProfileServices();
+                if (newState == BluetoothAdapter.STATE_OFF) {
+                    // If Bluetooth is off, send service down event to proxy objects, and unbind
+                    if (DBG) Log.d(TAG, "Bluetooth is complete turn off");
+                    if (canUnbindBluetoothService()) {
+                        if (DBG) Log.d(TAG, "Good to unbind!");
                         sendBluetoothServiceDownCallback();
                         unbindAndFinish();
+                        sendBleStateChanged(prevState, newState);
+                        // Don't broadcast as it has already been broadcast before
+                        isStandardBroadcast = false;
                     }
+
+                } else if (!intermediate_off) {
+                    // connect to GattService
+                    if (DBG) Log.d(TAG, "Bluetooth is in LE only mode");
+                    if (mBluetoothGatt != null) {
+                        if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp");
+                        onBluetoothGattServiceUp();
+                    } else {
+                        if (DBG) Log.d(TAG, "Binding Bluetooth GATT service");
+                        if (mContext.getPackageManager().hasSystemFeature(
+                                                        PackageManager.FEATURE_BLUETOOTH_LE)) {
+                            Intent i = new Intent(IBluetoothGatt.class.getName());
+                            doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
+                        }
+                    }
+                    sendBleStateChanged(prevState, newState);
+                    //Don't broadcase this as std intent
+                    isStandardBroadcast = false;
+
+                } else if (intermediate_off){
+                    if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode");
+                    // For LE only mode, broadcast as is
+                    sendBleStateChanged(prevState, newState);
+                    sendBluetoothStateCallback(false); // BT is OFF for general users
+                    // Broadcast as STATE_OFF
+                    newState = BluetoothAdapter.STATE_OFF;
+                    sendBrEdrDownCallback();
                 }
+            } else if (newState == BluetoothAdapter.STATE_ON) {
+                boolean isUp = (newState==BluetoothAdapter.STATE_ON);
+                sendBluetoothStateCallback(isUp);
+                sendBleStateChanged(prevState, newState);
+
+            } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
+                || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
+                sendBleStateChanged(prevState, newState);
+                isStandardBroadcast = false;
+
+            } else if (newState == BluetoothAdapter.STATE_TURNING_ON
+                || newState == BluetoothAdapter.STATE_TURNING_OFF) {
+                sendBleStateChanged(prevState, newState);
             }
 
-            //Send broadcast message to everyone else
-            Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
-            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
-            intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-            if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
-                    BLUETOOTH_PERM);
+            if (isStandardBroadcast) {
+                if (prevState == BluetoothAdapter.STATE_BLE_ON) {
+                    // Show prevState of BLE_ON as OFF to standard users
+                    prevState = BluetoothAdapter.STATE_OFF;
+                }
+                Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+                intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
+                intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d9ef766..64a924a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -19,7 +19,7 @@
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -89,6 +89,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
 
@@ -691,16 +692,15 @@
         return mNextNetworkRequestId++;
     }
 
-    private void assignNextNetId(NetworkAgentInfo nai) {
+    private int reserveNetId() {
         synchronized (mNetworkForNetId) {
             for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
                 int netId = mNextNetId;
                 if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
                 // Make sure NetID unused.  http://b/16815182
-                if (mNetworkForNetId.get(netId) == null) {
-                    nai.network = new Network(netId);
-                    mNetworkForNetId.put(netId, nai);
-                    return;
+                if (!mNetIdInUse.get(netId)) {
+                    mNetIdInUse.put(netId, true);
+                    return netId;
                 }
             }
         }
@@ -721,7 +721,9 @@
                     info = new NetworkInfo(nai.networkInfo);
                     lp = new LinkProperties(nai.linkProperties);
                     nc = new NetworkCapabilities(nai.networkCapabilities);
-                    network = new Network(nai.network);
+                    // Network objects are outwardly immutable so there is no point to duplicating.
+                    // Duplicating also precludes sharing socket factories and connection pools.
+                    network = nai.network;
                     subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null;
                 }
                 info.setType(networkType);
@@ -789,7 +791,9 @@
                 info = new NetworkInfo(nai.networkInfo);
                 lp = new LinkProperties(nai.linkProperties);
                 nc = new NetworkCapabilities(nai.networkCapabilities);
-                network = new Network(nai.network);
+                // Network objects are outwardly immutable so there is no point to duplicating.
+                // Duplicating also precludes sharing socket factories and connection pools.
+                network = nai.network;
                 subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null;
             }
         }
@@ -855,6 +859,28 @@
         return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
     }
 
+    @Override
+    public Network getActiveNetwork() {
+        enforceAccessPermission();
+        final int uid = Binder.getCallingUid();
+        final int user = UserHandle.getUserId(uid);
+        int vpnNetId = NETID_UNSET;
+        synchronized (mVpns) {
+            final Vpn vpn = mVpns.get(user);
+            if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId();
+        }
+        NetworkAgentInfo nai;
+        if (vpnNetId != NETID_UNSET) {
+            synchronized (mNetworkForNetId) {
+                nai = mNetworkForNetId.get(vpnNetId);
+            }
+            if (nai != null) return nai.network;
+        }
+        nai = getDefaultNetwork();
+        if (nai != null && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) nai = null;
+        return nai != null ? nai.network : null;
+    }
+
     /**
      * Find the first Provisioning network.
      *
@@ -967,13 +993,13 @@
     @Override
     public Network[] getAllNetworks() {
         enforceAccessPermission();
-        final ArrayList<Network> result = new ArrayList();
         synchronized (mNetworkForNetId) {
+            final Network[] result = new Network[mNetworkForNetId.size()];
             for (int i = 0; i < mNetworkForNetId.size(); i++) {
-                result.add(new Network(mNetworkForNetId.valueAt(i).network));
+                result[i] = mNetworkForNetId.valueAt(i).network;
             }
+            return result;
         }
-        return result.toArray(new Network[result.size()]);
     }
 
     private NetworkCapabilities getNetworkCapabilitiesAndValidation(NetworkAgentInfo nai) {
@@ -1341,7 +1367,6 @@
 
     public void sendConnectedBroadcast(NetworkInfo info) {
         enforceConnectivityInternalPermission();
-        sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE);
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
 
@@ -1938,6 +1963,7 @@
                 if (nai != null) {
                     synchronized (mNetworkForNetId) {
                         mNetworkForNetId.remove(nai.network.netId);
+                        mNetIdInUse.delete(nai.network.netId);
                     }
                     // Just in case.
                     mLegacyTypeTracker.remove(nai);
@@ -1981,6 +2007,7 @@
             mLegacyTypeTracker.remove(nai);
             synchronized (mNetworkForNetId) {
                 mNetworkForNetId.remove(nai.network.netId);
+                mNetIdInUse.delete(nai.network.netId);
             }
             // Since we've lost the network, go through all the requests that
             // it was satisfying and see if any other factory can satisfy them.
@@ -2432,25 +2459,27 @@
     public void reportInetCondition(int networkType, int percentage) {
         NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
         if (nai == null) return;
-        boolean isGood = percentage > 50;
-        // Revalidate if the app report does not match our current validated state.
-        if (isGood != nai.lastValidated) {
-            // Make the message logged by reportBadNetwork below less confusing.
-            if (DBG && isGood) log("reportInetCondition: type=" + networkType + " ok, revalidate");
-            reportBadNetwork(nai.network);
-        }
+        reportNetworkConnectivity(nai.network, percentage > 50);
     }
 
-    public void reportBadNetwork(Network network) {
+    public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
         enforceAccessPermission();
         enforceInternetPermission();
 
-        if (network == null) return;
-
-        final int uid = Binder.getCallingUid();
-        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        NetworkAgentInfo nai;
+        if (network == null) {
+            nai = getDefaultNetwork();
+        } else {
+            nai = getNetworkAgentInfoForNetwork(network);
+        }
         if (nai == null) return;
-        if (DBG) log("reportBadNetwork(" + nai.name() + ") by " + uid);
+        // Revalidate if the app report does not match our current validated state.
+        if (hasConnectivity == nai.lastValidated) return;
+        final int uid = Binder.getCallingUid();
+        if (DBG) {
+            log("reportNetworkConnectivity(" + nai.network.netId + ", " + hasConnectivity +
+                    ") by " + uid);
+        }
         synchronized (nai) {
             // Validating an uncreated network could result in a call to rematchNetworkAndRequests()
             // which isn't meant to work on uncreated networks.
@@ -2462,6 +2491,16 @@
         }
     }
 
+    public void captivePortalAppResponse(Network network, int response, String actionToken) {
+        if (response == ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS) {
+            enforceConnectivityInternalPermission();
+        }
+        final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        if (nai == null) return;
+        nai.networkMonitor.sendMessage(NetworkMonitor.CMD_CAPTIVE_PORTAL_APP_FINISHED, response, 0,
+                actionToken);
+    }
+
     public ProxyInfo getDefaultProxy() {
         // this information is already available as a world read/writable jvm property
         // so this API change wouldn't have a benifit.  It also breaks the passing
@@ -2860,23 +2899,6 @@
         }
     }
 
-    public int findConnectionTypeForIface(String iface) {
-        enforceConnectivityInternalPermission();
-
-        if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE;
-
-        synchronized(mNetworkForNetId) {
-            for (int i = 0; i < mNetworkForNetId.size(); i++) {
-                NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
-                LinkProperties lp = nai.linkProperties;
-                if (lp != null && iface.equals(lp.getInterfaceName()) && nai.networkInfo != null) {
-                    return nai.networkInfo.getType();
-                }
-            }
-        }
-        return ConnectivityManager.TYPE_NONE;
-    }
-
     @Override
     public int checkMobileProvisioning(int suggestedTimeOutMs) {
         // TODO: Remove?  Any reason to trigger a provisioning check?
@@ -3130,7 +3152,7 @@
                 loge("Starting user already has a VPN");
                 return;
             }
-            userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, this, userId);
+            userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
             mVpns.put(userId, userVpn);
         }
     }
@@ -3275,6 +3297,24 @@
         }
     }
 
+    @Override
+    public boolean requestBwUpdate(Network network) {
+        enforceAccessPermission();
+        NetworkAgentInfo nai = null;
+        if (network == null) {
+            return false;
+        }
+        synchronized (mNetworkForNetId) {
+            nai = mNetworkForNetId.get(network.netId);
+        }
+        if (nai != null) {
+            nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
+            return true;
+        }
+        return false;
+    }
+
+
     private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
         // if UID is restricted, don't allow them to bring up metered APNs
         if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
@@ -3382,14 +3422,23 @@
      * and the are the highest scored network available.
      * the are keyed off the Requests requestId.
      */
+    // TODO: Yikes, this is accessed on multiple threads: add synchronization.
     private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
             new SparseArray<NetworkAgentInfo>();
 
+    // NOTE: Accessed on multiple threads, must be synchronized on itself.
+    @GuardedBy("mNetworkForNetId")
     private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
             new SparseArray<NetworkAgentInfo>();
+    // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
+    // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
+    // there may not be a strict 1:1 correlation between the two.
+    @GuardedBy("mNetworkForNetId")
+    private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
 
     // NetworkAgentInfo keyed off its connecting messenger
     // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
+    // NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
     private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
             new HashMap<Messenger, NetworkAgentInfo>();
 
@@ -3404,7 +3453,7 @@
         return nai == getDefaultNetwork();
     }
 
-    public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+    public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkMisc networkMisc) {
         enforceConnectivityInternalPermission();
@@ -3412,20 +3461,23 @@
         // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
         // satisfies mDefaultRequest.
         NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
-            new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
-            new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
-            new NetworkMisc(networkMisc), mDefaultRequest);
+                new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
+                linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest);
         synchronized (this) {
             nai.networkMonitor.systemReady = mSystemReady;
         }
         if (DBG) log("registerNetworkAgent " + nai);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
+        return nai.network.netId;
     }
 
     private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
         if (VDBG) log("Got NetworkAgent Messenger");
         mNetworkAgentInfos.put(na.messenger, na);
-        assignNextNetId(na);
+        synchronized (mNetworkForNetId) {
+            mNetworkForNetId.put(na.network.netId, na);
+        }
         na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
         NetworkInfo networkInfo = na.networkInfo;
         na.networkInfo = null;
@@ -4149,9 +4201,6 @@
             }
             intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
                     mDefaultInetConditionPublished);
-            final Intent immediateIntent = new Intent(intent);
-            immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
-            sendStickyBroadcast(immediateIntent);
             sendStickyBroadcast(intent);
             if (newDefaultAgent != null) {
                 sendConnectedBroadcast(newDefaultAgent.networkInfo);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index f3e0bbc..2d1f939 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -40,7 +40,10 @@
  */
 public class NetworkAgentInfo {
     public NetworkInfo networkInfo;
-    public Network network;
+    // This Network object should always be used if possible, so as to encourage reuse of the
+    // enclosed socket factory and connection pool.  Avoid creating other Network objects.
+    // This Network object is always valid.
+    public final Network network;
     public LinkProperties linkProperties;
     public NetworkCapabilities networkCapabilities;
     public final NetworkMonitor networkMonitor;
@@ -83,12 +86,12 @@
     // Used by ConnectivityService to keep track of 464xlat.
     public Nat464Xlat clatd;
 
-    public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, NetworkInfo info,
+    public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
             NetworkMisc misc, NetworkRequest defaultRequest) {
         this.messenger = messenger;
         asyncChannel = ac;
-        network = null;
+        network = net;
         networkInfo = info;
         linkProperties = lp;
         networkCapabilities = nc;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 87f78c1..3dc5426 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -87,17 +87,6 @@
     private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
             "android.permission.ACCESS_NETWORK_CONDITIONS";
 
-    // Keep these in sync with CaptivePortalLoginActivity.java.
-    // Intent broadcast from CaptivePortalLogin indicating sign-in is complete.
-    // Extras:
-    //     EXTRA_TEXT       = netId
-    //     LOGGED_IN_RESULT = one of the CAPTIVE_PORTAL_APP_RETURN_* values below.
-    //     RESPONSE_TOKEN   = data fragment from launching Intent
-    private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN =
-            "android.net.netmon.captive_portal_logged_in";
-    private static final String LOGGED_IN_RESULT = "result";
-    private static final String RESPONSE_TOKEN = "response_token";
-
     // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
     // The network should be used as a default internet connection.  It was found to be:
     // 1. a functioning network providing internet access, or
@@ -170,11 +159,12 @@
 
     /**
      * Message to self indicating captive portal app finished.
-     * arg1 = one of: CAPTIVE_PORTAL_APP_RETURN_APPEASED,
+     * arg1 = one of: CAPTIVE_PORTAL_APP_RETURN_DISMISSED,
      *                CAPTIVE_PORTAL_APP_RETURN_UNWANTED,
      *                CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS
+     * obj = mCaptivePortalLoggedInResponseToken as String
      */
-    private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9;
+    public static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9;
 
     /**
      * Request ConnectivityService display provisioning notification.
@@ -185,26 +175,11 @@
     public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 10;
 
     /**
-     * Message to self indicating sign-in app bypassed captive portal.
+     * Message to self indicating sign-in app should be launched.
+     * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the
+     * user touches the sign in notification.
      */
-    private static final int EVENT_APP_BYPASSED_CAPTIVE_PORTAL = BASE + 11;
-
-    /**
-     * Message to self indicating no sign-in app responded.
-     */
-    private static final int EVENT_NO_APP_RESPONSE = BASE + 12;
-
-    /**
-     * Message to self indicating sign-in app indicates sign-in is not possible.
-     */
-    private static final int EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLE = BASE + 13;
-
-    /**
-     * Return codes from captive portal sign-in app.
-     */
-    public static final int CAPTIVE_PORTAL_APP_RETURN_APPEASED = 0;
-    public static final int CAPTIVE_PORTAL_APP_RETURN_UNWANTED = 1;
-    public static final int CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS = 2;
+    private static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11;
 
     private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
     // Default to 30s linger time-out.
@@ -220,7 +195,7 @@
     // If a network is not validated, make one attempt every 10 mins to see if it starts working.
     private static final int REEVALUATE_PAUSE_MS = 10*60*1000;
     private static final int PERIODIC_ATTEMPTS = 1;
-    // When an application calls reportBadNetwork, only make one attempt.
+    // When an application calls reportNetworkConnectivity, only make one attempt.
     private static final int REEVALUATE_ATTEMPTS = 1;
     private final int mReevaluateDelayMs;
     private int mReevaluateToken = 0;
@@ -259,7 +234,7 @@
     private final State mCaptivePortalState = new CaptivePortalState();
     private final State mLingeringState = new LingeringState();
 
-    private CaptivePortalLoggedInBroadcastReceiver mCaptivePortalLoggedInBroadcastReceiver = null;
+    private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
     private String mCaptivePortalLoggedInResponseToken = null;
 
     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
@@ -323,9 +298,9 @@
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
                     if (DBG) log("Disconnected - quitting");
-                    if (mCaptivePortalLoggedInBroadcastReceiver != null) {
-                        mContext.unregisterReceiver(mCaptivePortalLoggedInBroadcastReceiver);
-                        mCaptivePortalLoggedInBroadcastReceiver = null;
+                    if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
+                        mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
+                        mLaunchCaptivePortalAppBroadcastReceiver = null;
                     }
                     quit();
                     return HANDLED;
@@ -336,14 +311,21 @@
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_CAPTIVE_PORTAL_APP_FINISHED:
-                    // Previous token was broadcast, come up with a new one.
+                    if (!mCaptivePortalLoggedInResponseToken.equals((String)message.obj))
+                        return HANDLED;
+                    // Previous token was sent out, come up with a new one.
                     mCaptivePortalLoggedInResponseToken = String.valueOf(new Random().nextLong());
                     switch (message.arg1) {
-                        case CAPTIVE_PORTAL_APP_RETURN_APPEASED:
-                        case CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS:
+                        case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_DISMISSED:
+                            sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */,
+                                    0 /* INITIAL_ATTEMPTS */);
+                            break;
+                        case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS:
+                            // TODO: Distinguish this from a network that actually validates.
+                            // Displaying the "!" on the system UI icon may still be a good idea.
                             transitionTo(mValidatedState);
                             break;
-                        case CAPTIVE_PORTAL_APP_RETURN_UNWANTED:
+                        case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_UNWANTED:
                             mUserDoesNotWant = true;
                             // TODO: Should teardown network.
                             transitionTo(mOfflineState);
@@ -421,6 +403,25 @@
     // is required.  This State takes care to clear the notification upon exit from the State.
     private class MaybeNotifyState extends State {
         @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString());
+            switch (message.what) {
+                case CMD_LAUNCH_CAPTIVE_PORTAL_APP:
+                    final Intent intent = new Intent(
+                            ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
+                    intent.putExtra(ConnectivityManager.EXTRA_NETWORK, mNetworkAgentInfo.network);
+                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_TOKEN,
+                            mCaptivePortalLoggedInResponseToken);
+                    intent.setFlags(
+                            Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
         public void exit() {
             Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0,
                     mNetworkAgentInfo.network.netId, null);
@@ -516,7 +517,9 @@
             mContext.registerReceiver(this, new IntentFilter(mAction));
         }
         public PendingIntent getPendingIntent() {
-            return PendingIntent.getBroadcast(mContext, 0, new Intent(mAction), 0);
+            final Intent intent = new Intent(mAction);
+            intent.setPackage(mContext.getPackageName());
+            return PendingIntent.getBroadcast(mContext, 0, intent, 0);
         }
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -524,48 +527,29 @@
         }
     }
 
-    private class CaptivePortalLoggedInBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Integer.parseInt(intent.getStringExtra(Intent.EXTRA_TEXT)) ==
-                    mNetworkAgentInfo.network.netId &&
-                    mCaptivePortalLoggedInResponseToken.equals(
-                            intent.getStringExtra(RESPONSE_TOKEN))) {
-                sendMessage(obtainMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED,
-                        Integer.parseInt(intent.getStringExtra(LOGGED_IN_RESULT)), 0));
-            }
-        }
-    }
-
     // Being in the CaptivePortalState State indicates a captive portal was detected and the user
     // has been shown a notification to sign-in.
     private class CaptivePortalState extends State {
+        private static final String ACTION_LAUNCH_CAPTIVE_PORTAL_APP =
+                "android.net.netmon.launchCaptivePortalApp";
+
         @Override
         public void enter() {
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo));
-
-            // Assemble Intent to launch captive portal sign-in app.
-            final Intent intent = new Intent(Intent.ACTION_SEND);
-            // Intent cannot use extras because PendingIntent.getActivity will merge matching
-            // Intents erasing extras.  Use data instead of extras to encode NetID.
-            intent.setData(Uri.fromParts("netid", Integer.toString(mNetworkAgentInfo.network.netId),
-                    mCaptivePortalLoggedInResponseToken));
-            intent.setComponent(new ComponentName("com.android.captiveportallogin",
-                    "com.android.captiveportallogin.CaptivePortalLoginActivity"));
-            intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
-
-            if (mCaptivePortalLoggedInBroadcastReceiver == null) {
+            // Create a CustomIntentReceiver that sends us a
+            // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user
+            // touches the notification.
+            if (mLaunchCaptivePortalAppBroadcastReceiver == null) {
                 // Wait for result.
-                mCaptivePortalLoggedInBroadcastReceiver =
-                        new CaptivePortalLoggedInBroadcastReceiver();
-                final IntentFilter filter = new IntentFilter(ACTION_CAPTIVE_PORTAL_LOGGED_IN);
-                mContext.registerReceiver(mCaptivePortalLoggedInBroadcastReceiver, filter);
+                mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver(
+                        ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(),
+                        CMD_LAUNCH_CAPTIVE_PORTAL_APP);
             }
-            // Initiate notification to sign-in.
+            // Display the sign in notification.
             Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1,
                     mNetworkAgentInfo.network.netId,
-                    PendingIntent.getActivity(mContext, 0, intent, 0));
+                    mLaunchCaptivePortalAppBroadcastReceiver.getPendingIntent());
             mConnectivityServiceHandler.sendMessage(message);
         }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8533f69..d9c96f2 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,9 +17,10 @@
 package com.android.server.connectivity;
 
 import static android.Manifest.permission.BIND_VPN_SERVICE;
-import static android.os.UserHandle.PER_USER_RANGE;
+import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.os.UserHandle.PER_USER_RANGE;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 
@@ -69,6 +70,7 @@
 import android.os.UserManager;
 import android.security.Credentials;
 import android.security.KeyStore;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -114,7 +116,6 @@
     private LegacyVpnRunner mLegacyVpnRunner;
     private PendingIntent mStatusIntent;
     private volatile boolean mEnableTeardown = true;
-    private final IConnectivityManager mConnService;
     private final INetworkManagementService mNetd;
     private VpnConfig mConfig;
     private NetworkAgent mNetworkAgent;
@@ -130,10 +131,9 @@
     private final int mUserHandle;
 
     public Vpn(Looper looper, Context context, INetworkManagementService netService,
-            IConnectivityManager connService, int userHandle) {
+            int userHandle) {
         mContext = context;
         mNetd = netService;
-        mConnService = connService;
         mUserHandle = userHandle;
         mLooper = looper;
 
@@ -340,6 +340,10 @@
         return mNetworkInfo;
     }
 
+    public int getNetId() {
+        return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
+    }
+
     private LinkProperties makeLinkProperties() {
         boolean allowIPv4 = mConfig.allowIPv4;
         boolean allowIPv6 = mConfig.allowIPv6;
@@ -1086,11 +1090,15 @@
             // registering
             mOuterInterface = mConfig.interfaze;
 
-            try {
-                mOuterConnection.set(
-                        mConnService.findConnectionTypeForIface(mOuterInterface));
-            } catch (Exception e) {
-                mOuterConnection.set(ConnectivityManager.TYPE_NONE);
+            if (!TextUtils.isEmpty(mOuterInterface)) {
+                final ConnectivityManager cm = ConnectivityManager.from(mContext);
+                for (Network network : cm.getAllNetworks()) {
+                    final LinkProperties lp = cm.getLinkProperties(network);
+                    if (lp != null && mOuterInterface.equals(lp.getInterfaceName())) {
+                        final NetworkInfo networkInfo = cm.getNetworkInfo(network);
+                        if (networkInfo != null) mOuterConnection.set(networkInfo.getType());
+                    }
+                }
             }
 
             IntentFilter filter = new IntentFilter();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index a8f6954..8034809 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -179,6 +179,13 @@
         }
     }
 
+    @ServiceThreadOnly
+    protected boolean handleUserControlPressed(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        wakeUpIfActiveSource();
+        return super.handleUserControlPressed(message);
+    }
+
     @Override
     @ServiceThreadOnly
     protected boolean handleSetStreamPath(HdmiCecMessage message) {
@@ -216,7 +223,12 @@
     }
 
     private void wakeUpIfActiveSource() {
-        if (mIsActiveSource && mService.isPowerStandbyOrTransient()) {
+        if (!mIsActiveSource) {
+            return;
+        }
+        // Wake up the device if the power is in standby mode, or its screen is off -
+        // which can happen if the device is holding a partial lock.
+        if (mService.isPowerStandbyOrTransient() || !mService.getPowerManager().isScreenOn()) {
             mService.wakeUp();
         }
     }
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 4c6cb17..b3d7287 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -91,14 +91,20 @@
     public synchronized void maybeStartTrackingJob(JobStatus job) {
         if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
             maybeStopTrackingJob(job);
+            boolean isInsert = false;
             ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
             while (it.hasPrevious()) {
                 JobStatus ts = it.previous();
                 if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
                     // Insert
+                    isInsert = true;
                     break;
                 }
             }
+            if(isInsert)
+            {
+                it.next();
+            }
             it.add(job);
             maybeUpdateAlarms(
                     job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 5ae6300..8079bec 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -434,7 +434,7 @@
                 checkSmsSuplInit(intent);
             } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
                 checkWapSuplInit(intent);
-            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE)) {
+            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                 // retrieve NetworkInfo result for this UID
                 NetworkInfo info =
                         intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
@@ -754,7 +754,7 @@
         intentFilter = new IntentFilter();
         intentFilter.addAction(ALARM_WAKEUP);
         intentFilter.addAction(ALARM_TIMEOUT);
-        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2be591b..a8746b4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -27,7 +27,7 @@
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
@@ -400,7 +400,7 @@
         mContext.registerReceiver(mScreenReceiver, screenFilter);
 
         // watch for network interfaces to be claimed
-        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
+        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
 
         // listen for package changes to update policy
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cc0a30a..6498dcc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -271,6 +271,7 @@
     static final int SCAN_TRUSTED_OVERLAY = 1<<9;
     static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10;
     static final int SCAN_REPLACING = 1<<11;
+    static final int SCAN_REQUIRE_KNOWN = 1<<12;
 
     static final int REMOVE_CHATTY = 1<<16;
 
@@ -1646,10 +1647,10 @@
             if (!mOnlyCore) {
                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                         SystemClock.uptimeMillis());
-                scanDirLI(mAppInstallDir, 0, scanFlags, 0);
+                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
 
                 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
-                        scanFlags, 0);
+                        scanFlags | SCAN_REQUIRE_KNOWN, 0);
 
                 /**
                  * Remove disable package settings for any updated system
@@ -5349,6 +5350,28 @@
                     + " already installed.  Skipping duplicate.");
         }
 
+        // If we're only installing presumed-existing packages, require that the
+        // scanned APK is both already known and at the path previously established
+        // for it.  Previously unknown packages we pick up normally, but if we have an
+        // a priori expectation about this package's install presence, enforce it.
+        if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
+            PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
+            if (known != null) {
+                if (DEBUG_PACKAGE_SCANNING) {
+                    Log.d(TAG, "Examining " + pkg.codePath
+                            + " and requiring known paths " + known.codePathString
+                            + " & " + known.resourcePathString);
+                }
+                if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
+                        || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
+                    throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
+                            "Application package " + pkg.packageName
+                            + " found at " + pkg.applicationInfo.getCodePath()
+                            + " but expected at " + known.codePathString + "; ignoring.");
+                }
+            }
+        }
+
         // Initialize package source and resource directories
         File destCodeFile = new File(pkg.applicationInfo.getCodePath());
         File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
diff --git a/services/net/java/android/net/dhcp/DhcpAckPacket.java b/services/net/java/android/net/dhcp/DhcpAckPacket.java
index 25b8093..c0e1d19 100644
--- a/services/net/java/android/net/dhcp/DhcpAckPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpAckPacket.java
@@ -29,9 +29,9 @@
      */
     private final Inet4Address mSrcIp;
 
-    DhcpAckPacket(int transId, boolean broadcast, Inet4Address serverAddress,
+    DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
                   Inet4Address clientIp, byte[] clientMac) {
-        super(transId, INADDR_ANY, clientIp, serverAddress, INADDR_ANY, clientMac, broadcast);
+        super(transId, secs, INADDR_ANY, clientIp, serverAddress, INADDR_ANY, clientMac, broadcast);
         mBroadcast = broadcast;
         mSrcIp = serverAddress;
     }
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 57cc251..e1d1787 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -92,6 +92,7 @@
     private static final boolean DBG = true;
     private static final boolean STATE_DBG = false;
     private static final boolean MSG_DBG = false;
+    private static final boolean PACKET_DBG = true;
 
     // Timers and timeouts.
     private static final int SECONDS = 1000;
@@ -153,6 +154,7 @@
     private byte[] mHwAddr;
     private PacketSocketAddress mInterfaceBroadcastAddr;
     private int mTransactionId;
+    private long mTransactionStartMillis;
     private DhcpResults mDhcpLease;
     private long mDhcpLeaseExpiry;
     private DhcpResults mOffer;
@@ -263,8 +265,9 @@
         }
     }
 
-    private void initTransactionId() {
+    private void startNewTransaction() {
         mTransactionId = mRandom.nextInt();
+        mTransactionStartMillis = SystemClock.elapsedRealtime();
     }
 
     private boolean initSockets() {
@@ -329,15 +332,24 @@
                     if (packet != null) {
                         maybeLog("Received packet: " + packet);
                         sendMessage(CMD_RECEIVED_PACKET, packet);
+                    } else if (PACKET_DBG) {
+                        Log.d(TAG,
+                                "Can't parse packet" + HexDump.dumpHexString(mPacket, 0, length));
                     }
-                } catch(IOException|ErrnoException e) {
-                    Log.e(TAG, "Read error", e);
+                } catch (IOException|ErrnoException e) {
+                    if (!stopped) {
+                        Log.e(TAG, "Read error", e);
+                    }
                 }
             }
             maybeLog("Stopping receive thread");
         }
     }
 
+    private short getSecs() {
+        return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000);
+    }
+
     private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) {
         try {
             if (to.equals(INADDR_BROADCAST)) {
@@ -356,7 +368,8 @@
 
     private boolean sendDiscoverPacket() {
         ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
-                DhcpPacket.ENCAP_L2, mTransactionId, mHwAddr, DO_UNICAST, REQUESTED_PARAMS);
+                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
+                DO_UNICAST, REQUESTED_PARAMS);
         return transmitPacket(packet, "DHCPDISCOVER", INADDR_BROADCAST);
     }
 
@@ -367,7 +380,7 @@
         int encap = to.equals(INADDR_BROADCAST) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
 
         ByteBuffer packet = DhcpPacket.buildRequestPacket(
-                encap, mTransactionId, clientAddress,
+                encap, mTransactionId, getSecs(), clientAddress,
                 DO_UNICAST, mHwAddr, requestedAddress,
                 serverAddress, REQUESTED_PARAMS, null);
         String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
@@ -663,7 +676,7 @@
         @Override
         public void enter() {
             super.enter();
-            initTransactionId();
+            startNewTransaction();
         }
 
         protected boolean sendPacket() {
@@ -770,7 +783,7 @@
         @Override
         public void enter() {
             super.enter();
-            initTransactionId();
+            startNewTransaction();
         }
 
         protected boolean sendPacket() {
diff --git a/services/net/java/android/net/dhcp/DhcpDeclinePacket.java b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java
index 9d985ac..7ecdea7 100644
--- a/services/net/java/android/net/dhcp/DhcpDeclinePacket.java
+++ b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java
@@ -26,10 +26,10 @@
     /**
      * Generates a DECLINE packet with the specified parameters.
      */
-    DhcpDeclinePacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+    DhcpDeclinePacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                       Inet4Address nextIp, Inet4Address relayIp,
                       byte[] clientMac) {
-        super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false);
+        super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false);
     }
 
     public String toString() {
@@ -53,6 +53,9 @@
      * Adds optional parameters to the DECLINE packet.
      */
     void finishPacket(ByteBuffer buffer) {
-        // None needed
+        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DECLINE);
+        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
+        // RFC 2131 says we MUST NOT include our common client TLVs or the parameter request list.
+        addTlvEnd(buffer);
     }
 }
diff --git a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
index a031080..91e6bd6 100644
--- a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
@@ -26,8 +26,8 @@
     /**
      * Generates a DISCOVER packet with the specified parameters.
      */
-    DhcpDiscoverPacket(int transId, byte[] clientMac, boolean broadcast) {
-        super(transId, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
+    DhcpDiscoverPacket(int transId, short secs, byte[] clientMac, boolean broadcast) {
+        super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
     }
 
     public String toString() {
@@ -52,6 +52,7 @@
      */
     void finishPacket(ByteBuffer buffer) {
         addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DISCOVER);
+        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
         addCommonClientTlvs(buffer);
         addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
         addTlvEnd(buffer);
diff --git a/services/net/java/android/net/dhcp/DhcpInformPacket.java b/services/net/java/android/net/dhcp/DhcpInformPacket.java
index 8bc7cdd..7a83466 100644
--- a/services/net/java/android/net/dhcp/DhcpInformPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpInformPacket.java
@@ -26,10 +26,10 @@
     /**
      * Generates an INFORM packet with the specified parameters.
      */
-    DhcpInformPacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+    DhcpInformPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                      Inet4Address nextIp, Inet4Address relayIp,
                      byte[] clientMac) {
-        super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false);
+        super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false);
     }
 
     public String toString() {
@@ -53,12 +53,9 @@
      * Adds additional parameters to the INFORM packet.
      */
     void finishPacket(ByteBuffer buffer) {
-        byte[] clientId = new byte[7];
-
-        clientId[0] = CLIENT_ID_ETHER;
-        System.arraycopy(mClientMac, 0, clientId, 1, 6);
-
-        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_REQUEST);
+        addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_INFORM);
+        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
+        addCommonClientTlvs(buffer);
         addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
         addTlvEnd(buffer);
     }
diff --git a/services/net/java/android/net/dhcp/DhcpNakPacket.java b/services/net/java/android/net/dhcp/DhcpNakPacket.java
index 1390ea7..6458232 100644
--- a/services/net/java/android/net/dhcp/DhcpNakPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpNakPacket.java
@@ -26,10 +26,10 @@
     /**
      * Generates a NAK packet with the specified parameters.
      */
-    DhcpNakPacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+    DhcpNakPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                   Inet4Address nextIp, Inet4Address relayIp,
                   byte[] clientMac) {
-        super(transId, INADDR_ANY, INADDR_ANY, nextIp, relayIp,
+        super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp,
             clientMac, false);
     }
 
diff --git a/services/net/java/android/net/dhcp/DhcpOfferPacket.java b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
index b1f3bbd..af41708 100644
--- a/services/net/java/android/net/dhcp/DhcpOfferPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
@@ -31,9 +31,9 @@
     /**
      * Generates a OFFER packet with the specified parameters.
      */
-    DhcpOfferPacket(int transId, boolean broadcast, Inet4Address serverAddress,
+    DhcpOfferPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress,
                     Inet4Address clientIp, byte[] clientMac) {
-        super(transId, INADDR_ANY, clientIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
+        super(transId, secs, INADDR_ANY, clientIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
         mSrcIp = serverAddress;
     }
 
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a232a6e..b923b1b 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -226,6 +226,11 @@
     protected final int mTransId;
 
     /**
+     * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
+     */
+    protected final short mSecs;
+
+    /**
      * The IP address of the client host.  This address is typically
      * proposed by the client (from an earlier DHCP negotiation) or
      * supplied by the server.
@@ -258,10 +263,11 @@
      */
     abstract void finishPacket(ByteBuffer buffer);
 
-    protected DhcpPacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
                          Inet4Address nextIp, Inet4Address relayIp,
                          byte[] clientMac, boolean broadcast) {
         mTransId = transId;
+        mSecs = secs;
         mClientIp = clientIp;
         mYourIp = yourIp;
         mNextIp = nextIp;
@@ -285,6 +291,16 @@
     }
 
     /**
+     * Returns the client ID. This follows RFC 2132 and is based on the hardware address.
+     */
+    public byte[] getClientId() {
+        byte[] clientId = new byte[mClientMac.length + 1];
+        clientId[0] = CLIENT_ID_ETHER;
+        System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
+        return clientId;
+    }
+
+    /**
      * Creates a new L3 packet (including IP header) containing the
      * DHCP udp packet.  This method relies upon the delegated method
      * finishPacket() to insert the per-packet contents.
@@ -347,7 +363,7 @@
         buf.put((byte) mClientMac.length); // Hardware Address Length
         buf.put((byte) 0); // Hop Count
         buf.putInt(mTransId);  // Transaction ID
-        buf.putShort((short) 0); // Elapsed Seconds
+        buf.putShort(mSecs); // Elapsed Seconds
 
         if (broadcast) {
             buf.putShort((short) 0x8000); // Flags
@@ -611,10 +627,22 @@
     /**
      * Reads a string of specified length from the buffer.
      */
-    private static String readAsciiString(ByteBuffer buf, int byteCount) {
+    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
         byte[] bytes = new byte[byteCount];
         buf.get(bytes);
-        return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
+        int length = bytes.length;
+        if (!nullOk) {
+            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
+            // name) are passed to netd via FrameworkListener, which refuses arguments containing
+            // null bytes. We don't do this by default because vendorInfo is an opaque string which
+            // could in theory contain null bytes.
+            for (length = 0; length < bytes.length; length++) {
+                if (bytes[length] == 0) {
+                    break;
+                }
+            }
+        }
+        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
     }
 
     /**
@@ -630,6 +658,7 @@
     {
         // bootp parameters
         int transactionId;
+        short secs;
         Inet4Address clientIp;
         Inet4Address yourIp;
         Inet4Address nextIp;
@@ -737,7 +766,7 @@
         byte addrLen = packet.get();
         byte hops = packet.get();
         transactionId = packet.getInt();
-        short elapsed = packet.getShort();
+        secs = packet.getShort();
         short bootpFlags = packet.getShort();
         boolean broadcast = (bootpFlags & 0x8000) != 0;
         byte[] ipv4addr = new byte[4];
@@ -797,7 +826,7 @@
                             break;
                         case DHCP_HOST_NAME:
                             expectedLen = optionLen;
-                            hostName = readAsciiString(packet, optionLen);
+                            hostName = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_MTU:
                             expectedLen = 2;
@@ -805,7 +834,7 @@
                             break;
                         case DHCP_DOMAIN_NAME:
                             expectedLen = optionLen;
-                            domainName = readAsciiString(packet, optionLen);
+                            domainName = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_BROADCAST_ADDRESS:
                             bcAddr = readIpAddress(packet);
@@ -834,7 +863,7 @@
                             break;
                         case DHCP_MESSAGE:
                             expectedLen = optionLen;
-                            message = readAsciiString(packet, optionLen);
+                            message = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_MAX_MESSAGE_SIZE:
                             expectedLen = 2;
@@ -850,7 +879,7 @@
                             break;
                         case DHCP_VENDOR_CLASS_ID:
                             expectedLen = optionLen;
-                            vendorId = readAsciiString(packet, optionLen);
+                            vendorId = readAsciiString(packet, optionLen, true);
                             break;
                         case DHCP_CLIENT_IDENTIFIER: { // Client identifier
                             byte[] id = new byte[optionLen];
@@ -880,33 +909,33 @@
             case -1: return null;
             case DHCP_MESSAGE_TYPE_DISCOVER:
                 newPacket = new DhcpDiscoverPacket(
-                    transactionId, clientMac, broadcast);
+                    transactionId, secs, clientMac, broadcast);
                 break;
             case DHCP_MESSAGE_TYPE_OFFER:
                 newPacket = new DhcpOfferPacket(
-                    transactionId, broadcast, ipSrc, yourIp, clientMac);
+                    transactionId, secs, broadcast, ipSrc, yourIp, clientMac);
                 break;
             case DHCP_MESSAGE_TYPE_REQUEST:
                 newPacket = new DhcpRequestPacket(
-                    transactionId, clientIp, clientMac, broadcast);
+                    transactionId, secs, clientIp, clientMac, broadcast);
                 break;
             case DHCP_MESSAGE_TYPE_DECLINE:
                 newPacket = new DhcpDeclinePacket(
-                    transactionId, clientIp, yourIp, nextIp, relayIp,
+                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
                     clientMac);
                 break;
             case DHCP_MESSAGE_TYPE_ACK:
                 newPacket = new DhcpAckPacket(
-                    transactionId, broadcast, ipSrc, yourIp, clientMac);
+                    transactionId, secs, broadcast, ipSrc, yourIp, clientMac);
                 break;
             case DHCP_MESSAGE_TYPE_NAK:
                 newPacket = new DhcpNakPacket(
-                    transactionId, clientIp, yourIp, nextIp, relayIp,
+                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
                     clientMac);
                 break;
             case DHCP_MESSAGE_TYPE_INFORM:
                 newPacket = new DhcpInformPacket(
-                    transactionId, clientIp, yourIp, nextIp, relayIp,
+                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
                     clientMac);
                 break;
             default:
@@ -986,9 +1015,9 @@
      * parameters.
      */
     public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
-        byte[] clientMac, boolean broadcast, byte[] expectedParams) {
+        short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
         DhcpPacket pkt = new DhcpDiscoverPacket(
-            transactionId, clientMac, broadcast);
+            transactionId, secs, clientMac, broadcast);
         pkt.mRequestedParams = expectedParams;
         return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
     }
@@ -1003,7 +1032,7 @@
         Inet4Address gateway, List<Inet4Address> dnsServers,
         Inet4Address dhcpServerIdentifier, String domainName) {
         DhcpPacket pkt = new DhcpOfferPacket(
-            transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
+            transactionId, (short) 0, broadcast, serverIpAddr, clientIpAddr, mac);
         pkt.mGateway = gateway;
         pkt.mDnsServers = dnsServers;
         pkt.mLeaseTime = timeout;
@@ -1023,7 +1052,7 @@
         Inet4Address gateway, List<Inet4Address> dnsServers,
         Inet4Address dhcpServerIdentifier, String domainName) {
         DhcpPacket pkt = new DhcpAckPacket(
-            transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
+            transactionId, (short) 0, broadcast, serverIpAddr, clientIpAddr, mac);
         pkt.mGateway = gateway;
         pkt.mDnsServers = dnsServers;
         pkt.mLeaseTime = timeout;
@@ -1039,7 +1068,7 @@
      */
     public static ByteBuffer buildNakPacket(int encap, int transactionId,
         Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) {
-        DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr,
+        DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr,
             serverIpAddr, serverIpAddr, serverIpAddr, mac);
         pkt.mMessage = "requested address not available";
         pkt.mRequestedIp = clientIpAddr;
@@ -1050,10 +1079,10 @@
      * Builds a DHCP-REQUEST packet from the required specified parameters.
      */
     public static ByteBuffer buildRequestPacket(int encap,
-        int transactionId, Inet4Address clientIp, boolean broadcast,
+        int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
         byte[] clientMac, Inet4Address requestedIpAddress,
         Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
-        DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp,
+        DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
             clientMac, broadcast);
         pkt.mRequestedIp = requestedIpAddress;
         pkt.mServerIdentifier = serverIdentifier;
diff --git a/services/net/java/android/net/dhcp/DhcpRequestPacket.java b/services/net/java/android/net/dhcp/DhcpRequestPacket.java
index 42b7b0c..4f9aa01 100644
--- a/services/net/java/android/net/dhcp/DhcpRequestPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpRequestPacket.java
@@ -28,9 +28,9 @@
     /**
      * Generates a REQUEST packet with the specified parameters.
      */
-    DhcpRequestPacket(int transId, Inet4Address clientIp, byte[] clientMac,
+    DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, byte[] clientMac,
                       boolean broadcast) {
-        super(transId, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
+        super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
     }
 
     public String toString() {
@@ -56,20 +56,14 @@
      * Adds the optional parameters to the client-generated REQUEST packet.
      */
     void finishPacket(ByteBuffer buffer) {
-        byte[] clientId = new byte[7];
-
-        // assemble client identifier
-        clientId[0] = CLIENT_ID_ETHER;
-        System.arraycopy(mClientMac, 0, clientId, 1, 6);
-
         addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_REQUEST);
+        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
         if (!INADDR_ANY.equals(mRequestedIp)) {
             addTlv(buffer, DHCP_REQUESTED_IP, mRequestedIp);
         }
         if (!INADDR_ANY.equals(mServerIdentifier)) {
             addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
         }
-        addTlv(buffer, DHCP_CLIENT_IDENTIFIER, clientId);
         addCommonClientTlvs(buffer);
         addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
         addTlvEnd(buffer);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index f25fc62..33979b1 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -10,6 +10,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     services.core \
     services.devicepolicy \
+    services.net \
     easymocklib \
     guava \
     mockito-target
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
new file mode 100644
index 0000000..4f7c7ec
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 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.dhcp;
+
+import android.net.NetworkUtils;
+import android.system.OsConstants;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.net.Inet4Address;
+import java.nio.ByteBuffer;
+
+import static android.net.dhcp.DhcpPacket.*;
+
+
+public class DhcpPacketTest extends TestCase {
+
+    private static Inet4Address SERVER_ADDR =
+            (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.1");
+    private static Inet4Address CLIENT_ADDR =
+            (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.234");
+    private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+    class TestDhcpPacket extends DhcpPacket {
+        private byte mType;
+        // TODO: Make this a map of option numbers to bytes instead.
+        private byte[] mDomainBytes, mVendorInfoBytes;
+
+        public TestDhcpPacket(byte type, byte[] domainBytes, byte[] vendorInfoBytes) {
+            super(0xdeadbeef, (short) 0, INADDR_ANY, CLIENT_ADDR, INADDR_ANY, INADDR_ANY,
+                  CLIENT_MAC, true);
+            mType = type;
+            mDomainBytes = domainBytes;
+            mVendorInfoBytes = vendorInfoBytes;
+        }
+
+        public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
+            ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
+            fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
+                         DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
+            return result;
+        }
+
+        public void finishPacket(ByteBuffer buffer) {
+            addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
+            if (mDomainBytes != null) {
+                addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
+            }
+            if (mVendorInfoBytes != null) {
+                addTlv(buffer, DHCP_VENDOR_CLASS_ID, mVendorInfoBytes);
+            }
+            addTlvEnd(buffer);
+        }
+
+        // Convenience method.
+        public ByteBuffer build() {
+            // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
+            ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
+            pkt.flip();
+            return pkt;
+        }
+    }
+
+    private void assertDomainAndVendorInfoParses(
+            String expectedDomain, byte[] domainBytes,
+            String expectedVendorInfo, byte[] vendorInfoBytes) {
+        ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER,
+                domainBytes, vendorInfoBytes).build();
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+        assertEquals(expectedDomain, offerPacket.mDomainName);
+        assertEquals(expectedVendorInfo, offerPacket.mVendorId);
+    }
+
+    @SmallTest
+    public void testDomainName() throws Exception {
+        byte[] nullByte = new byte[] { 0x00 };
+        byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
+        byte[] nonNullDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
+        };
+        byte[] trailingNullDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
+        };
+        byte[] embeddedNullsDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
+        };
+        byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
+
+        byte[] meteredEmbeddedNull = metered.clone();
+        meteredEmbeddedNull[7] = (char) 0;
+
+        byte[] meteredTrailingNull = metered.clone();
+        meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
+
+        assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
+        assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
+        assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
+        assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
+                                        "ANDROID\u0000METERED", meteredEmbeddedNull);
+        assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
+                                        "ANDROID_METERE\u0000", meteredTrailingNull);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index c198900..48d8ffb 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -16,7 +16,7 @@
 
 package com.android.server;
 
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -157,7 +157,7 @@
 //        mMobile.link.addRoute(MOBILE_ROUTE_V6);
 //        mMobile.doReturnDefaults();
 //
-//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION);
 //        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
 //        nextConnBroadcast.get();
 //
@@ -177,7 +177,7 @@
 //        mMobile.link.addRoute(MOBILE_ROUTE_V6);
 //        mMobile.doReturnDefaults();
 //
-//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION);
 //        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
 //        nextConnBroadcast.get();
 //
@@ -193,7 +193,7 @@
 //        // expect that mobile will be torn down
 //        doReturn(true).when(mMobile.tracker).teardown();
 //
-//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION);
 //        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mWifi.info).sendToTarget();
 //        nextConnBroadcast.get();
 //
@@ -212,7 +212,7 @@
 //        mMobile.link.clear();
 //        mMobile.doReturnDefaults();
 //
-//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+//        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION);
 //        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
 //        nextConnBroadcast.get();
 //
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 0b4d42e..72a458b 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -18,7 +18,7 @@
 
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -597,7 +597,7 @@
         future = expectMeteredIfacesChanged();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         future.get();
         verifyAndReset();
 
@@ -708,7 +708,7 @@
             future = expectMeteredIfacesChanged(TEST_IFACE);
 
             replay();
-            mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+            mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
             future.get();
             verifyAndReset();
         }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 7383478..00af71d 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -18,7 +18,7 @@
 
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
@@ -191,7 +191,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -245,7 +245,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -336,7 +336,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // modify some number on wifi, and trigger poll event
@@ -388,7 +388,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some traffic on first network
@@ -430,7 +430,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
         verifyAndReset();
 
@@ -476,7 +476,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some traffic
@@ -545,7 +545,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some traffic
@@ -579,7 +579,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
         verifyAndReset();
 
@@ -616,7 +616,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some traffic for two apps
@@ -682,7 +682,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some initial traffic
@@ -747,7 +747,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some tethering traffic
@@ -787,7 +787,7 @@
         expectNetworkStatsPoll();
 
         replay();
-        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE));
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
         verifyAndReset();
 
         // create some traffic, but only for DEV, and across 1.5 buckets
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 9c03319..465c5f4 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -25,9 +24,7 @@
 /**
  *  Encapsulates the telecom audio state, including the current audio routing, supported audio
  *  routing and mute.
- *  @hide
  */
-@SystemApi
 public final class AudioState implements Parcelable {
     /** Direct the audio stream through the device's earpiece. */
     public static final int ROUTE_EARPIECE      = 0x00000001;
@@ -47,21 +44,13 @@
      */
     public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
 
-    /** Bit mask of all possible audio routes.
-     *
-     * @hide
-     */
-    public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
+    /** Bit mask of all possible audio routes. */
+    private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
             ROUTE_SPEAKER;
 
-    /** Note: Deprecated, please do not use if possible. */
-    @SystemApi public final boolean isMuted;
-
-    /** Note: Deprecated, please do not use if possible. */
-    @SystemApi public final int route;
-
-    /** Note: Deprecated, please do not use if possible. */
-    @SystemApi public final int supportedRouteMask;
+    private final boolean isMuted;
+    private final int route;
+    private final int supportedRouteMask;
 
     public AudioState(boolean muted, int route, int supportedRouteMask) {
         this.isMuted = muted;
@@ -97,7 +86,6 @@
                 audioRouteToString(supportedRouteMask));
     }
 
-    /** @hide */
     public static String audioRouteToString(int route) {
         if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
             return "UNKNOWN";
diff --git a/telecomm/java/android/telecom/AuthenticatorService.java b/telecomm/java/android/telecom/AuthenticatorService.java
index 39717c3..1e43c71 100644
--- a/telecomm/java/android/telecom/AuthenticatorService.java
+++ b/telecomm/java/android/telecom/AuthenticatorService.java
@@ -28,6 +28,8 @@
 /**
  * A generic stub account authenticator service often used for sync adapters that do not directly
  * involve accounts.
+ *
+ * @hide
  */
 public class AuthenticatorService extends Service {
     private static Authenticator mAuthenticator;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 436f20a..bea4f75 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -30,10 +30,7 @@
 
 /**
  * Represents an ongoing phone call that the in-call app should present to the user.
- *
- * {@hide}
  */
-@SystemApi
 public final class Call {
     /**
      * The state of a {@code Call} when newly created.
@@ -91,8 +88,6 @@
      * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
      * extras. Used to pass the phone accounts to display on the front end to the user in order to
      * select phone accounts to (for example) place a call.
-     *
-     * @hide
      */
     public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
 
@@ -142,40 +137,34 @@
 
         /**
          * Local device supports receiving video.
-         * @hide
          */
         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
 
         /**
          * Local device supports transmitting video.
-         * @hide
          */
         public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
 
         /**
          * Local device supports bidirectional video calling.
-         * @hide
          */
-        public static final int CAPABILITY_SUPPORTS_VT_LOCAL =
+        public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
                 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
 
         /**
          * Remote device supports receiving video.
-         * @hide
          */
         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
 
         /**
          * Remote device supports transmitting video.
-         * @hide
          */
         public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
 
         /**
          * Remote device supports bidirectional video calling.
-         * @hide
          */
-        public static final int CAPABILITY_SUPPORTS_VT_REMOTE =
+        public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
                 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
 
         /**
@@ -187,35 +176,25 @@
          * Call is able to be individually disconnected when in a {@code Conference}.
          */
         public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
-        
+
         /**
          * Whether the call is a generic conference, where we do not know the precise state of
          * participants in the conference (eg. on CDMA).
-         *
-         * @hide
          */
         public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
 
         /**
          * Call is using high definition audio.
-         * @hide
          */
         public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
 
         /**
          * Call is using WIFI.
-         * @hide
          */
         public static final int CAPABILITY_WIFI = 0x00010000;
 
-        //******************************************************************************************
-        // Next CAPABILITY value: 0x00020000
-        //******************************************************************************************
-
         /**
          * Indicates that the current device callback number should be shown.
-         *
-         * @hide
          */
         public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
 
@@ -225,8 +204,20 @@
          */
         public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
 
+        /**
+         * Call can be upgraded to a video call.
+         * @hide
+         */
+        public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
+
+        /**
+         * For video calls, indicates whether the outgoing video for the call can be paused using
+         * the {@link android.telecom.VideoProfile.VideoState#PAUSED} VideoState.
+         */
+        public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
+
         //******************************************************************************************
-        // Next CAPABILITY value: 0x00080000
+        // Next CAPABILITY value: 0x00200000
         //******************************************************************************************
 
         private final Uri mHandle;
@@ -249,7 +240,6 @@
          * @param capabilities A bit field of capabilities.
          * @param capability The capability to check capabilities for.
          * @return Whether the specified capability is supported.
-         * @hide
          */
         public static boolean can(int capabilities, int capability) {
             return (capabilities & capability) != 0;
@@ -260,7 +250,6 @@
          *
          * @param capability The capability to check capabilities for.
          * @return Whether the specified capability is supported.
-         * @hide
          */
         public boolean can(int capability) {
             return can(mCallCapabilities, capability);
@@ -302,8 +291,8 @@
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
             }
-            if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL)) {
-                builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL");
+            if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
+                builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
             }
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
@@ -311,8 +300,8 @@
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
             }
-            if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE)) {
-                builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE");
+            if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
+                builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
             }
             if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
                 builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
@@ -329,6 +318,12 @@
             if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
                 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
             }
+            if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
+                builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
+            }
+            if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
+                builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -401,7 +396,7 @@
          * periodically, but user interfaces should not rely on this to display any "call time
          * clock".
          */
-        public long getConnectTimeMillis() {
+        public final long getConnectTimeMillis() {
             return mConnectTimeMillis;
         }
 
@@ -506,7 +501,7 @@
         }
     }
 
-    public static abstract class Listener {
+    public static abstract class Callback {
         /**
          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
          *
@@ -565,7 +560,6 @@
          *
          * @param call The {@code Call} invoking this method.
          * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
-         * @hide
          */
         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
 
@@ -591,13 +585,21 @@
         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
     }
 
+    /**
+     * @deprecated Use {@code Call.Callback} instead.
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    public static abstract class Listener extends Callback { }
+
     private final Phone mPhone;
     private final String mTelecomCallId;
     private final InCallAdapter mInCallAdapter;
     private final List<String> mChildrenIds = new ArrayList<>();
     private final List<Call> mChildren = new ArrayList<>();
     private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
-    private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
+    private final List<Callback> mCallbacks = new CopyOnWriteArrayList<>();
     private final List<Call> mConferenceableCalls = new ArrayList<>();
     private final List<Call> mUnmodifiableConferenceableCalls =
             Collections.unmodifiableList(mConferenceableCalls);
@@ -692,8 +694,8 @@
      * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
      *
      * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
-     * {@code Call} will pause playing the tones and notify listeners via
-     * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app
+     * {@code Call} will pause playing the tones and notify callbacks via
+     * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
      * should display to the user an indication of this state and an affordance to continue
      * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
      * app should invoke the {@link #postDialContinue(boolean)} method.
@@ -818,7 +820,6 @@
      * Obtains an object that can be used to display video from this {@code Call}.
      *
      * @return An {@code Call.VideoCall}.
-     * @hide
      */
     public InCallService.VideoCall getVideoCall() {
         return mVideoCall;
@@ -835,25 +836,52 @@
     }
 
     /**
+     * Registers a callback to this {@code Call}.
+     *
+     * @param callback A {@code Callback}.
+     */
+    public void registerCallback(Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    /**
+     * Unregisters a callback from this {@code Call}.
+     *
+     * @param callback A {@code Callback}.
+     */
+    public void unregisterCallback(Callback callback) {
+        if (callback != null) {
+            mCallbacks.remove(callback);
+        }
+    }
+
+    /**
      * Adds a listener to this {@code Call}.
      *
      * @param listener A {@code Listener}.
+     * @deprecated Use {@link #registerCallback} instead.
+     * @hide
      */
+    @Deprecated
+    @SystemApi
     public void addListener(Listener listener) {
-        mListeners.add(listener);
+        registerCallback(listener);
     }
 
     /**
      * Removes a listener from this {@code Call}.
      *
      * @param listener A {@code Listener}.
+     * @deprecated Use {@link #unregisterCallback} instead.
+     * @hide
      */
+    @Deprecated
+    @SystemApi
     public void removeListener(Listener listener) {
-        if (listener != null) {
-            mListeners.remove(listener);
-        }
+        unregisterCallback(listener);
     }
 
+
     /** {@hide} */
     Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
         mPhone = phone;
@@ -896,7 +924,8 @@
                     Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
         }
 
-        boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
+        boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
+                !Objects.equals(mVideoCall, parcelableCall.getVideoCall());
         if (videoCallChanged) {
             mVideoCall = parcelableCall.getVideoCall();
         }
@@ -984,56 +1013,56 @@
     }
 
     private void fireStateChanged(int newState) {
-        for (Listener listener : mListeners) {
-            listener.onStateChanged(this, newState);
+        for (Callback callback : mCallbacks) {
+            callback.onStateChanged(this, newState);
         }
     }
 
     private void fireParentChanged(Call newParent) {
-        for (Listener listener : mListeners) {
-            listener.onParentChanged(this, newParent);
+        for (Callback callback : mCallbacks) {
+            callback.onParentChanged(this, newParent);
         }
     }
 
     private void fireChildrenChanged(List<Call> children) {
-        for (Listener listener : mListeners) {
-            listener.onChildrenChanged(this, children);
+        for (Callback callback : mCallbacks) {
+            callback.onChildrenChanged(this, children);
         }
     }
 
     private void fireDetailsChanged(Details details) {
-        for (Listener listener : mListeners) {
-            listener.onDetailsChanged(this, details);
+        for (Callback callback : mCallbacks) {
+            callback.onDetailsChanged(this, details);
         }
     }
 
     private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) {
-        for (Listener listener : mListeners) {
-            listener.onCannedTextResponsesLoaded(this, cannedTextResponses);
+        for (Callback callback : mCallbacks) {
+            callback.onCannedTextResponsesLoaded(this, cannedTextResponses);
         }
     }
 
     private void fireVideoCallChanged(InCallService.VideoCall videoCall) {
-        for (Listener listener : mListeners) {
-            listener.onVideoCallChanged(this, videoCall);
+        for (Callback callback : mCallbacks) {
+            callback.onVideoCallChanged(this, videoCall);
         }
     }
 
     private void firePostDialWait(String remainingPostDialSequence) {
-        for (Listener listener : mListeners) {
-            listener.onPostDialWait(this, remainingPostDialSequence);
+        for (Callback callback : mCallbacks) {
+            callback.onPostDialWait(this, remainingPostDialSequence);
         }
     }
 
     private void fireCallDestroyed() {
-        for (Listener listener : mListeners) {
-            listener.onCallDestroyed(this);
+        for (Callback callback : mCallbacks) {
+            callback.onCallDestroyed(this);
         }
     }
 
     private void fireConferenceableCallsChanged() {
-        for (Listener listener : mListeners) {
-            listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
+        for (Callback callback : mCallbacks) {
+            callback.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls);
         }
     }
 
diff --git a/telecomm/java/android/telecom/CallProperties.java b/telecomm/java/android/telecom/CallProperties.java
index b1b82e2..1721a39 100644
--- a/telecomm/java/android/telecom/CallProperties.java
+++ b/telecomm/java/android/telecom/CallProperties.java
@@ -18,7 +18,6 @@
 
 /**
  * Defines properties of a phone call which may be affected by changes to the call.
- * @hide
  */
 public class CallProperties {
     /** Call is currently in a conference call. */
diff --git a/telecomm/java/android/telecom/CallState.java b/telecomm/java/android/telecom/CallState.java
index bd9223a..5584226 100644
--- a/telecomm/java/android/telecom/CallState.java
+++ b/telecomm/java/android/telecom/CallState.java
@@ -16,17 +16,12 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
-
 /**
  * Defines call-state constants of the different states in which a call can exist. Although states
  * have the notion of normal transitions, due to the volatile nature of telephony systems, code
  * that uses these states should be resilient to unexpected state changes outside of what is
  * considered traditional.
- *
- * {@hide}
  */
-@SystemApi
 public final class CallState {
 
     private CallState() {}
diff --git a/telecomm/java/android/telecom/CameraCapabilities.java b/telecomm/java/android/telecom/CameraCapabilities.java
index f968c13..6242956 100644
--- a/telecomm/java/android/telecom/CameraCapabilities.java
+++ b/telecomm/java/android/telecom/CameraCapabilities.java
@@ -21,21 +21,10 @@
 
 /**
  * Represents the camera capabilities important to a Video Telephony provider.
- * @hide
  */
 public final class CameraCapabilities implements Parcelable {
 
     /**
-     * Whether the camera supports zoom.
-     */
-    private final boolean mZoomSupported;
-
-    /**
-     * The maximum zoom supported by the camera.
-     */
-    private final float mMaxZoom;
-
-    /**
      * The width of the camera video in pixels.
      */
     private final int mWidth;
@@ -46,18 +35,40 @@
     private final int mHeight;
 
     /**
+     * Whether the camera supports zoom.
+     */
+    private final boolean mZoomSupported;
+
+    /**
+     * The maximum zoom supported by the camera.
+     */
+    private final float mMaxZoom;
+
+    /**
      * Create a call camera capabilities instance.
      *
-     * @param zoomSupported True when camera supports zoom.
-     * @param maxZoom Maximum zoom supported by camera.
      * @param width The width of the camera video (in pixels).
      * @param height The height of the camera video (in pixels).
      */
-    public CameraCapabilities(boolean zoomSupported, float maxZoom, int width, int height) {
-        mZoomSupported = zoomSupported;
-        mMaxZoom = maxZoom;
+    public CameraCapabilities(int width, int height) {
+        this(width, height, false, 1.0f);
+    }
+
+    /**
+     * Create a call camera capabilities instance that optionally
+     * supports zoom.
+     *
+     * @param width The width of the camera video (in pixels).
+     * @param height The height of the camera video (in pixels).
+     * @param zoomSupported True when camera supports zoom.
+     * @param maxZoom Maximum zoom supported by camera.
+     * @hide
+     */
+    public CameraCapabilities(int width, int height, boolean zoomSupported, float maxZoom) {
         mWidth = width;
         mHeight = height;
+        mZoomSupported = zoomSupported;
+        mMaxZoom = maxZoom;
     }
 
     /**
@@ -73,12 +84,12 @@
                  */
                 @Override
                 public CameraCapabilities createFromParcel(Parcel source) {
-                    boolean supportsZoom = source.readByte() != 0;
-                    float maxZoom = source.readFloat();
                     int width = source.readInt();
                     int height = source.readInt();
+                    boolean supportsZoom = source.readByte() != 0;
+                    float maxZoom = source.readFloat();
 
-                    return new CameraCapabilities(supportsZoom, maxZoom, width, height);
+                    return new CameraCapabilities(width, height, supportsZoom, maxZoom);
                 }
 
                 @Override
@@ -108,24 +119,10 @@
      */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
-        dest.writeFloat(getMaxZoom());
         dest.writeInt(getWidth());
         dest.writeInt(getHeight());
-    }
-
-    /**
-     * Whether the camera supports zoom.
-     */
-    public boolean isZoomSupported() {
-        return mZoomSupported;
-    }
-
-    /**
-     * The maximum zoom supported by the camera.
-     */
-    public float getMaxZoom() {
-        return mMaxZoom;
+        dest.writeByte((byte) (isZoomSupported() ? 1 : 0));
+        dest.writeFloat(getMaxZoom());
     }
 
     /**
@@ -141,4 +138,20 @@
     public int getHeight() {
         return mHeight;
     }
+
+    /**
+     * Whether the camera supports zoom.
+     * @hide
+     */
+    public boolean isZoomSupported() {
+        return mZoomSupported;
+    }
+
+    /**
+     * The maximum zoom supported by the camera.
+     * @hide
+     */
+    public float getMaxZoom() {
+        return mMaxZoom;
+    }
 }
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 33bbb29..3acf945 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,27 +16,26 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
+import android.telecom.Connection.VideoProvider;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 /**
  * Represents a conference call which can contain any number of {@link Connection} objects.
- * @hide
  */
-@SystemApi
 public abstract class Conference implements IConferenceable {
 
     /**
      * Used to indicate that the conference connection time is not specified.  If not specified,
      * Telecom will set the connect time.
      */
-    public static long CONNECT_TIME_NOT_SPECIFIED = 0;
+    public static final long CONNECT_TIME_NOT_SPECIFIED = 0;
 
     /** @hide */
     public abstract static class Listener {
@@ -49,6 +48,9 @@
         public void onDestroyed(Conference conference) {}
         public void onConnectionCapabilitiesChanged(
                 Conference conference, int connectionCapabilities) {}
+        public void onVideoStateChanged(Conference c, int videoState) { }
+        public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {}
+        public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
     }
 
     private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -59,13 +61,14 @@
     private final List<Connection> mUnmodifiableConferenceableConnections =
             Collections.unmodifiableList(mConferenceableConnections);
 
-    protected PhoneAccountHandle mPhoneAccount;
+    private PhoneAccountHandle mPhoneAccount;
     private AudioState mAudioState;
     private int mState = Connection.STATE_NEW;
     private DisconnectCause mDisconnectCause;
     private int mConnectionCapabilities;
     private String mDisconnectMessage;
     private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
+    private StatusHints mStatusHints;
 
     private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
         @Override
@@ -112,11 +115,6 @@
         return mState;
     }
 
-    /** @hide */
-    @Deprecated public final int getCapabilities() {
-        return getConnectionCapabilities();
-    }
-
     /**
      * Returns the capabilities of a conference. See {@code CAPABILITY_*} constants in class
      * {@link Connection} for valid values.
@@ -180,6 +178,22 @@
     }
 
     /**
+     * Returns VideoProvider of the primary call. This can be null.
+     *  @hide
+     */
+    public VideoProvider getVideoProvider() {
+        return null;
+    }
+
+    /**
+     * Returns video state of the primary call.
+     *  @hide
+     */
+    public int getVideoState() {
+        return VideoProfile.VideoState.AUDIO_ONLY;
+    }
+
+    /**
      * Invoked when the Conference and all it's {@link Connection}s should be disconnected.
      */
     public void onDisconnect() {}
@@ -281,11 +295,6 @@
         return mDisconnectCause;
     }
 
-    /** @hide */
-    @Deprecated public final void setCapabilities(int connectionCapabilities) {
-        setConnectionCapabilities(connectionCapabilities);
-    }
-
     /**
      * Sets the capabilities of a conference. See {@code CAPABILITY_*} constants of class
      * {@link Connection} for valid values.
@@ -309,6 +318,7 @@
      * @return True if the connection was successfully added.
      */
     public final boolean addConnection(Connection connection) {
+        Log.d(this, "Connection=%s, connection=", connection);
         if (connection != null && !mChildConnections.contains(connection)) {
             if (connection.setConference(this)) {
                 mChildConnections.add(connection);
@@ -355,6 +365,38 @@
         fireOnConferenceableConnectionsChanged();
     }
 
+    /**
+     * Set the video state for the conference.
+     * Valid values: {@link VideoProfile.VideoState#AUDIO_ONLY},
+     * {@link VideoProfile.VideoState#BIDIRECTIONAL},
+     * {@link VideoProfile.VideoState#TX_ENABLED},
+     * {@link VideoProfile.VideoState#RX_ENABLED}.
+     *
+     * @param videoState The new video state.
+     * @hide
+     */
+    public final void setVideoState(Connection c, int videoState) {
+        Log.d(this, "setVideoState Conference: %s Connection: %s VideoState: %s",
+                this, c, videoState);
+        for (Listener l : mListeners) {
+            l.onVideoStateChanged(this, videoState);
+        }
+    }
+
+    /**
+     * Sets the video connection provider.
+     *
+     * @param videoProvider The video provider.
+     * @hide
+     */
+    public final void setVideoProvider(Connection c, Connection.VideoProvider videoProvider) {
+        Log.d(this, "setVideoProvider Conference: %s Connection: %s VideoState: %s",
+                this, c, videoProvider);
+        for (Listener l : mListeners) {
+            l.onVideoProviderChanged(this, videoProvider);
+        }
+    }
+
     private final void fireOnConferenceableConnectionsChanged() {
         for (Listener l : mListeners) {
             l.onConferenceableConnectionsChanged(this, getConferenceableConnections());
@@ -444,7 +486,7 @@
      *
      * @return The time the {@code Conference} has been connected.
      */
-    public long getConnectTimeMillis() {
+    public final long getConnectTimeMillis() {
         return mConnectTimeMillis;
     }
 
@@ -484,4 +526,34 @@
         }
         mConferenceableConnections.clear();
     }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US,
+                "[State: %s,Capabilites: %s, VideoState: %s, VideoProvider: %s, ThisObject %s]",
+                Connection.stateToString(mState),
+                Call.Details.capabilitiesToString(mConnectionCapabilities),
+                getVideoState(),
+                getVideoProvider(),
+                super.toString());
+    }
+
+    /**
+     * Sets the label and icon status to display in the InCall UI.
+     *
+     * @param statusHints The status label and icon to set.
+     */
+    public final void setStatusHints(StatusHints statusHints) {
+        mStatusHints = statusHints;
+        for (Listener l : mListeners) {
+            l.onStatusHintsChanged(this, statusHints);
+        }
+    }
+
+    /**
+     * @return The status hints for this conference.
+     */
+    public final StatusHints getStatusHints() {
+        return mStatusHints;
+    }
 }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index bab064e..9ced4ae 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -19,7 +19,6 @@
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
@@ -29,6 +28,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -44,9 +44,7 @@
  * Implementations are then responsible for updating the state of the {@code Connection}, and
  * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no
  * longer used and associated resources may be recovered.
- * @hide
  */
-@SystemApi
 public abstract class Connection implements IConferenceable {
 
     public static final int STATE_INITIALIZING = 0;
@@ -121,7 +119,7 @@
      * Local device supports bidirectional video calling.
      * @hide
      */
-    public static final int CAPABILITY_SUPPORTS_VT_LOCAL =
+    public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
             CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
 
     /**
@@ -140,7 +138,7 @@
      * Remote device supports bidirectional video calling.
      * @hide
      */
-    public static final int CAPABILITY_SUPPORTS_VT_REMOTE =
+    public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
             CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
 
     /**
@@ -186,8 +184,21 @@
     */
     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
 
+    /**
+     * Call can be upgraded to a video call.
+     * @hide
+     */
+    public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
+
+    /**
+     * For video calls, indicates whether the outgoing video for the call can be paused using
+     * the {@link android.telecom.VideoProfile.VideoState#PAUSED} VideoState.
+     * @hide
+     */
+    public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x00080000
+    // Next CAPABILITY value: 0x00200000
     //**********************************************************************************************
 
     // Flag controlling whether PII is emitted into the logs
@@ -267,8 +278,8 @@
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
             builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
         }
-        if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL");
+        if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
+            builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
         }
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
@@ -276,8 +287,8 @@
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
         }
-        if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE)) {
-            builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE");
+        if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
+            builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
         }
         if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
             builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
@@ -294,6 +305,12 @@
         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
             builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
         }
+        if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
+            builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
+        }
+        if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
+            builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
+        }
         builder.append("]");
         return builder.toString();
     }
@@ -324,7 +341,6 @@
         public void onConferenceStarted() {}
     }
 
-    /** @hide */
     public static abstract class VideoProvider {
 
         /**
@@ -377,7 +393,17 @@
          */
         public static final int SESSION_MODIFY_REQUEST_INVALID = 3;
 
-        private static final int MSG_SET_VIDEO_CALLBACK = 1;
+        /**
+         * Session modify request timed out.
+         */
+        public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4;
+
+        /**
+         * Session modify request rejected by remote UE.
+         */
+        public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5;
+
+        private static final int MSG_ADD_VIDEO_CALLBACK = 1;
         private static final int MSG_SET_CAMERA = 2;
         private static final int MSG_SET_PREVIEW_SURFACE = 3;
         private static final int MSG_SET_DISPLAY_SURFACE = 4;
@@ -388,11 +414,16 @@
         private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
         private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10;
         private static final int MSG_SET_PAUSE_IMAGE = 11;
+        private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
 
         private final VideoProvider.VideoProviderHandler
                 mMessageHandler = new VideoProvider.VideoProviderHandler();
         private final VideoProvider.VideoProviderBinder mBinder;
-        private IVideoCallback mVideoCallback;
+
+        /**
+         * Stores a list of the video callbacks, keyed by IBinder.
+         */
+        private HashMap<IBinder, IVideoCallback> mVideoCallbacks = new HashMap<>();
 
         /**
          * Default handler used to consolidate binder method calls onto a single thread.
@@ -401,9 +432,29 @@
             @Override
             public void handleMessage(Message msg) {
                 switch (msg.what) {
-                    case MSG_SET_VIDEO_CALLBACK:
-                        mVideoCallback = IVideoCallback.Stub.asInterface((IBinder) msg.obj);
+                    case MSG_ADD_VIDEO_CALLBACK: {
+                        IBinder binder = (IBinder) msg.obj;
+                        IVideoCallback callback = IVideoCallback.Stub
+                                .asInterface((IBinder) msg.obj);
+                        if (mVideoCallbacks.containsKey(binder)) {
+                            Log.i(this, "addVideoProvider - skipped; already present.");
+                            break;
+                        }
+                        mVideoCallbacks.put(binder, callback);
+                        Log.i(this, "addVideoProvider  "+ mVideoCallbacks.size());
                         break;
+                    }
+                    case MSG_REMOVE_VIDEO_CALLBACK: {
+                        IBinder binder = (IBinder) msg.obj;
+                        IVideoCallback callback = IVideoCallback.Stub
+                                .asInterface((IBinder) msg.obj);
+                        if (!mVideoCallbacks.containsKey(binder)) {
+                            Log.i(this, "removeVideoProvider - skipped; not present.");
+                            break;
+                        }
+                        mVideoCallbacks.remove(binder);
+                        break;
+                    }
                     case MSG_SET_CAMERA:
                         onSetCamera((String) msg.obj);
                         break;
@@ -444,9 +495,14 @@
          * IVideoProvider stub implementation.
          */
         private final class VideoProviderBinder extends IVideoProvider.Stub {
-            public void setVideoCallback(IBinder videoCallbackBinder) {
+            public void addVideoCallback(IBinder videoCallbackBinder) {
                 mMessageHandler.obtainMessage(
-                        MSG_SET_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
+                        MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
+            }
+
+            public void removeVideoCallback(IBinder videoCallbackBinder) {
+                mMessageHandler.obtainMessage(
+                        MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
             }
 
             public void setCamera(String cameraId) {
@@ -462,7 +518,8 @@
             }
 
             public void setDeviceOrientation(int rotation) {
-                mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget();
+                mMessageHandler.obtainMessage(
+                        MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
             }
 
             public void setZoom(float value) {
@@ -583,21 +640,23 @@
         public abstract void onSetPauseImage(String uri);
 
         /**
-         * Invokes callback method defined in In-Call UI.
+         * Invokes callback method defined in listening {@link InCallService} implementations.
          *
          * @param videoProfile The requested video connection profile.
          */
         public void receiveSessionModifyRequest(VideoProfile videoProfile) {
-            if (mVideoCallback != null) {
+            if (mVideoCallbacks != null) {
                 try {
-                    mVideoCallback.receiveSessionModifyRequest(videoProfile);
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.receiveSessionModifyRequest(videoProfile);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
         }
 
         /**
-         * Invokes callback method defined in In-Call UI.
+         * Invokes callback method defined in listening {@link InCallService} implementations.
          *
          * @param status Status of the session modify request.  Valid values are
          *               {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS},
@@ -608,17 +667,19 @@
          */
         public void receiveSessionModifyResponse(int status,
                 VideoProfile requestedProfile, VideoProfile responseProfile) {
-            if (mVideoCallback != null) {
+            if (mVideoCallbacks != null) {
                 try {
-                    mVideoCallback.receiveSessionModifyResponse(
-                            status, requestedProfile, responseProfile);
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.receiveSessionModifyResponse(status, requestedProfile,
+                                responseProfile);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
         }
 
         /**
-         * Invokes callback method defined in In-Call UI.
+         * Invokes callback method defined in listening {@link InCallService} implementations.
          *
          * Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE},
          * {@link VideoProvider#SESSION_EVENT_RX_RESUME},
@@ -628,52 +689,76 @@
          * @param event The event.
          */
         public void handleCallSessionEvent(int event) {
-            if (mVideoCallback != null) {
+            if (mVideoCallbacks != null) {
                 try {
-                    mVideoCallback.handleCallSessionEvent(event);
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.handleCallSessionEvent(event);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
         }
 
         /**
-         * Invokes callback method defined in In-Call UI.
+         * Invokes callback method defined in listening {@link InCallService} implementations.
          *
          * @param width  The updated peer video width.
          * @param height The updated peer video height.
          */
         public void changePeerDimensions(int width, int height) {
-            if (mVideoCallback != null) {
+            if (mVideoCallbacks != null) {
                 try {
-                    mVideoCallback.changePeerDimensions(width, height);
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.changePeerDimensions(width, height);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
         }
 
         /**
-         * Invokes callback method defined in In-Call UI.
+         * Invokes callback method defined in listening {@link InCallService} implementations.
          *
          * @param dataUsage The updated data usage.
          */
-        public void changeCallDataUsage(int dataUsage) {
-            if (mVideoCallback != null) {
+        public void changeCallDataUsage(long dataUsage) {
+            if (mVideoCallbacks != null) {
                 try {
-                    mVideoCallback.changeCallDataUsage(dataUsage);
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.changeCallDataUsage(dataUsage);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
         }
 
         /**
-         * Invokes callback method defined in In-Call UI.
+         * Invokes callback method defined in listening {@link InCallService} implementations.
          *
          * @param cameraCapabilities The changed camera capabilities.
          */
         public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) {
-            if (mVideoCallback != null) {
+            if (mVideoCallbacks != null) {
                 try {
-                    mVideoCallback.changeCameraCapabilities(cameraCapabilities);
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.changeCameraCapabilities(cameraCapabilities);
+                    }
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Invokes callback method defined in listening {@link InCallService} implementations.
+         *
+         * @param videoQuality The updated video quality.
+         */
+        public void changeVideoQuality(int videoQuality) {
+            if (mVideoCallbacks != null) {
+                try {
+                    for (IVideoCallback callback : mVideoCallbacks.values()) {
+                        callback.changeVideoQuality(videoQuality);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
@@ -901,11 +986,6 @@
         return mConnectionCapabilities;
     }
 
-    /** @hide */
-    @SystemApi @Deprecated public final int getCallCapabilities() {
-        return getConnectionCapabilities();
-    }
-
     /**
      * Sets the value of the {@link #getAddress()} property.
      *
@@ -1022,7 +1102,6 @@
         }
     }
 
-    /** @hide */
     public final VideoProvider getVideoProvider() {
         return mVideoProvider;
     }
@@ -1093,11 +1172,6 @@
         }
     }
 
-    /** @hide */
-    @SystemApi @Deprecated public final void setCallCapabilities(int connectionCapabilities) {
-        setConnectionCapabilities(connectionCapabilities);
-    }
-
     /**
      * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants.
      *
@@ -1487,6 +1561,7 @@
 
     /**
      * Notifies listeners that a conference call has been started.
+     * @hide
      */
     protected void notifyConferenceStarted() {
         for (Listener l : mListeners) {
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index f691c17..71b481b 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -25,9 +24,7 @@
 /**
  * Simple data container encapsulating a request to some entity to
  * create a new {@link Connection}.
- * @hide
  */
-@SystemApi
 public final class ConnectionRequest implements Parcelable {
 
     // TODO: Token to limit recursive invocations
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index dfdc3e1..aad7fcb 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -17,7 +17,6 @@
 package android.telecom;
 
 import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -72,9 +71,7 @@
  * receives call-commands such as answer, reject, hold and disconnect.
  * <p>
  * When there are no more live calls, telecom will unbind from the {@code ConnectionService}.
- * @hide
  */
-@SystemApi
 public abstract class ConnectionService extends Service {
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -415,6 +412,27 @@
                     Connection.capabilitiesToString(connectionCapabilities));
             mAdapter.setConnectionCapabilities(id, connectionCapabilities);
         }
+
+        @Override
+        public void onVideoStateChanged(Conference c, int videoState) {
+            String id = mIdByConference.get(c);
+            Log.d(this, "onVideoStateChanged set video state %d", videoState);
+            mAdapter.setVideoState(id, videoState);
+        }
+
+        @Override
+        public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {
+            String id = mIdByConference.get(c);
+            Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
+                    videoProvider);
+            mAdapter.setVideoProvider(id, videoProvider);
+        }
+
+        @Override
+        public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {
+            String id = mIdByConference.get(conference);
+            mAdapter.setStatusHints(id, statusHints);
+        }
     };
 
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
@@ -508,6 +526,8 @@
         @Override
         public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) {
             String id = mIdByConnection.get(c);
+            Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
+                    videoProvider);
             mAdapter.setVideoProvider(id, videoProvider);
         }
 
@@ -871,6 +891,8 @@
      * @param conference The new conference object.
      */
     public final void addConference(Conference conference) {
+        Log.d(this, "addConference: conference=%s", conference);
+
         String id = addConferenceInternal(conference);
         if (id != null) {
             List<String> connectionIds = new ArrayList<>(2);
@@ -884,8 +906,15 @@
                     conference.getState(),
                     conference.getConnectionCapabilities(),
                     connectionIds,
-                    conference.getConnectTimeMillis());
+                    conference.getVideoProvider() == null ?
+                            null : conference.getVideoProvider().getInterface(),
+                    conference.getVideoState(),
+                    conference.getConnectTimeMillis(),
+                    conference.getStatusHints());
+
             mAdapter.addConferenceCall(id, parcelableConference);
+            mAdapter.setVideoProvider(id, conference.getVideoProvider());
+            mAdapter.setVideoState(id, conference.getVideoState());
 
             // Go through any child calls and set the parent.
             for (Connection connection : conference.getConnections()) {
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 130d676..73bcd0c 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.media.ToneGenerator;
@@ -30,9 +29,7 @@
  * user. It is the responsibility of the {@link ConnectionService} to provide localized versions of
  * the label and description. It also may contain a reason for the disconnect, which is intended for
  * logging and not for display to the user.
- * @hide
  */
-@SystemApi
 public final class DisconnectCause implements Parcelable {
 
     /** Disconnected because of an unknown or unspecified reason. */
diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java
index 5b8e4ab..928570e 100644
--- a/telecomm/java/android/telecom/GatewayInfo.java
+++ b/telecomm/java/android/telecom/GatewayInfo.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -34,17 +33,13 @@
  * <li> Call the appropriate gateway address.
  * <li> Display information about how the call is being routed to the user.
  * </ol>
- * @hide
  */
-@SystemApi
 public class GatewayInfo implements Parcelable {
 
     private final String mGatewayProviderPackageName;
     private final Uri mGatewayAddress;
     private final Uri mOriginalAddress;
 
-    /** @hide */
-    @SystemApi
     public GatewayInfo(String packageName, Uri gatewayUri, Uri originalAddress) {
         mGatewayProviderPackageName = packageName;
         mGatewayAddress = gatewayUri;
diff --git a/telecomm/java/android/telecom/IConferenceable.java b/telecomm/java/android/telecom/IConferenceable.java
index 095d7cb..a9be20b 100644
--- a/telecomm/java/android/telecom/IConferenceable.java
+++ b/telecomm/java/android/telecom/IConferenceable.java
@@ -16,16 +16,11 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
-
 /**
  * Interface used to identify entities with which another entity can participate in a conference
  * call with.  The {@link ConnectionService} implementation will only recognize
  * {@link IConferenceable}s which are {@link Connection}s or {@link Conference}s.
- *
- * @hide
  */
-@SystemApi
 public interface IConferenceable {
 
 }
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index a85e84d..020a33f 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -16,8 +16,8 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
 import android.os.Handler;
@@ -31,15 +31,14 @@
 import com.android.internal.telecom.IInCallService;
 
 import java.lang.String;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * This service is implemented by any app that wishes to provide the user-interface for managing
  * phone calls. Telecom binds to this service while there exists a live (active or incoming) call,
  * and uses it to notify the in-call app of any live and and recently disconnected calls.
- *
- * {@hide}
  */
-@SystemApi
 public abstract class InCallService extends Service {
 
     /**
@@ -67,6 +66,7 @@
             switch (msg.what) {
                 case MSG_SET_IN_CALL_ADAPTER:
                     mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
+                    mPhone.addListener(mPhoneListener);
                     onPhoneCreated(mPhone);
                     break;
                 case MSG_ADD_CALL:
@@ -148,6 +148,39 @@
         }
     }
 
+    private Phone.Listener mPhoneListener = new Phone.Listener() {
+        /** ${inheritDoc} */
+        @Override
+        public void onAudioStateChanged(Phone phone, AudioState audioState) {
+            InCallService.this.onAudioStateChanged(audioState);
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void onBringToForeground(Phone phone, boolean showDialpad) {
+            InCallService.this.onBringToForeground(showDialpad);
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void onCallAdded(Phone phone, Call call) {
+            InCallService.this.onCallAdded(call);
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void onCallRemoved(Phone phone, Call call) {
+            InCallService.this.onCallRemoved(call);
+        }
+
+        /** ${inheritDoc} */
+        @Override
+        public void onCanAddCallChanged(Phone phone, boolean canAddCall) {
+            InCallService.this.onCanAddCallChanged(canAddCall);
+        }
+
+    };
+
     private Phone mPhone;
 
     public InCallService() {
@@ -165,8 +198,14 @@
             mPhone = null;
 
             oldPhone.destroy();
+            // destroy sets all the calls to disconnected if any live ones still exist. Therefore,
+            // it is important to remove the Listener *after* the call to destroy so that
+            // InCallService.on* callbacks are appropriately called.
+            oldPhone.removeListener(mPhoneListener);
+
             onPhoneDestroyed(oldPhone);
         }
+
         return false;
     }
 
@@ -176,19 +215,79 @@
      * @return The {@code Phone} object associated with this {@code InCallService}, or {@code null}
      *         if the {@code InCallService} is not in a state where it has an associated
      *         {@code Phone}.
+     * @hide
+     * @deprecated Use direct methods on InCallService instead of {@link Phone}.
      */
+    @SystemApi
+    @Deprecated
     public Phone getPhone() {
         return mPhone;
     }
 
     /**
+     * Obtains the current list of {@code Call}s to be displayed by this in-call experience.
+     *
+     * @return A list of the relevant {@code Call}s.
+     */
+    public final List<Call> getCalls() {
+        return mPhone == null ? Collections.<Call>emptyList() : mPhone.getCalls();
+    }
+
+    /**
+     * Returns if the device can support additional calls.
+     *
+     * @return Whether the phone supports adding more calls.
+     */
+    public final boolean canAddCall() {
+        return mPhone == null ? false : mPhone.canAddCall();
+    }
+
+    /**
+     * Obtains the current phone call audio state.
+     *
+     * @return An object encapsulating the audio state. Returns null if the service is not
+     *         fully initialized.
+     */
+    public final AudioState getAudioState() {
+        return mPhone == null ? null : mPhone.getAudioState();
+    }
+
+    /**
+     * Sets the microphone mute state. When this request is honored, there will be change to
+     * the {@link #getAudioState()}.
+     *
+     * @param state {@code true} if the microphone should be muted; {@code false} otherwise.
+     */
+    public final void setMuted(boolean state) {
+        if (mPhone != null) {
+            mPhone.setMuted(state);
+        }
+    }
+
+    /**
+     * Sets the audio route (speaker, bluetooth, etc...).  When this request is honored, there will
+     * be change to the {@link #getAudioState()}.
+     *
+     * @param route The audio route to use.
+     */
+    public final void setAudioRoute(int route) {
+        if (mPhone != null) {
+            mPhone.setAudioRoute(route);
+        }
+    }
+
+    /**
      * Invoked when the {@code Phone} has been created. This is a signal to the in-call experience
      * to start displaying in-call information to the user. Each instance of {@code InCallService}
      * will have only one {@code Phone}, and this method will be called exactly once in the lifetime
      * of the {@code InCallService}.
      *
      * @param phone The {@code Phone} object associated with this {@code InCallService}.
+     * @hide
+     * @deprecated Use direct methods on InCallService instead of {@link Phone}.
      */
+    @SystemApi
+    @Deprecated
     public void onPhoneCreated(Phone phone) {
     }
 
@@ -199,23 +298,81 @@
      * call to {@link #onPhoneCreated(Phone)}.
      *
      * @param phone The {@code Phone} object associated with this {@code InCallService}.
+     * @hide
+     * @deprecated Use direct methods on InCallService instead of {@link Phone}.
      */
+    @SystemApi
+    @Deprecated
     public void onPhoneDestroyed(Phone phone) {
     }
 
     /**
+     * Called when the audio state changes.
+     *
+     * @param audioState The new {@link AudioState}.
+     */
+    public void onAudioStateChanged(AudioState audioState) {
+    }
+
+    /**
+     * Called to bring the in-call screen to the foreground. The in-call experience should
+     * respond immediately by coming to the foreground to inform the user of the state of
+     * ongoing {@code Call}s.
+     *
+     * @param showDialpad If true, put up the dialpad when the screen is shown.
+     */
+    public void onBringToForeground(boolean showDialpad) {
+    }
+
+    /**
+     * Called when a {@code Call} has been added to this in-call session. The in-call user
+     * experience should add necessary state listeners to the specified {@code Call} and
+     * immediately start to show the user information about the existence
+     * and nature of this {@code Call}. Subsequent invocations of {@link #getCalls()} will
+     * include this {@code Call}.
+     *
+     * @param call A newly added {@code Call}.
+     */
+    public void onCallAdded(Call call) {
+    }
+
+    /**
+     * Called when a {@code Call} has been removed from this in-call session. The in-call user
+     * experience should remove any state listeners from the specified {@code Call} and
+     * immediately stop displaying any information about this {@code Call}.
+     * Subsequent invocations of {@link #getCalls()} will no longer include this {@code Call}.
+     *
+     * @param call A newly removed {@code Call}.
+     */
+    public void onCallRemoved(Call call) {
+    }
+
+    /**
+     * Called when the ability to add more calls changes.  If the phone cannot
+     * support more calls then {@code canAddCall} is set to {@code false}.  If it can, then it
+     * is set to {@code true}. This can be used to control the visibility of UI to add more calls.
+     *
+     * @param canAddCall Indicates whether an additional call can be added.
+     */
+    public void onCanAddCallChanged(boolean canAddCall) {
+    }
+
+    /**
      * Class to invoke functionality related to video calls.
-     * @hide
      */
     public static abstract class VideoCall {
 
         /**
-         * Sets a listener to invoke callback methods in the InCallUI after performing video
-         * telephony actions.
+         * Registers a callback to receive commands and state changes for video calls.
          *
-         * @param videoCallListener The call video client.
+         * @param callback The video call callback.
          */
-        public abstract void setVideoCallListener(VideoCall.Listener videoCallListener);
+        public abstract void registerCallback(VideoCall.Callback callback);
+
+        /**
+         * Unregisters the callback set via {@link #registerCallback(Callback)}.
+         */
+        public abstract void unregisterCallback();
 
         /**
          * Sets the camera to be used for video recording in a video call.
@@ -258,7 +415,7 @@
         /**
          * Issues a request to modify the properties of the current session.  The request is sent to
          * the remote device where it it handled by
-         * {@link VideoCall.Listener#onSessionModifyRequestReceived}.
+         * {@link VideoCall.Callback#onSessionModifyRequestReceived}.
          * Some examples of session modification requests: upgrade call from audio to video,
          * downgrade call from video to audio, pause video.
          *
@@ -270,9 +427,9 @@
          * Provides a response to a request to change the current call session video
          * properties.
          * This is in response to a request the InCall UI has received via
-         * {@link VideoCall.Listener#onSessionModifyRequestReceived}.
+         * {@link VideoCall.Callback#onSessionModifyRequestReceived}.
          * The response is handled on the remove device by
-         * {@link VideoCall.Listener#onSessionModifyResponseReceived}.
+         * {@link VideoCall.Callback#onSessionModifyResponseReceived}.
          *
          * @param responseProfile The response call video properties.
          */
@@ -281,14 +438,14 @@
         /**
          * Issues a request to the video provider to retrieve the camera capabilities.
          * Camera capabilities are reported back to the caller via
-         * {@link VideoCall.Listener#onCameraCapabilitiesChanged(CameraCapabilities)}.
+         * {@link VideoCall.Callback#onCameraCapabilitiesChanged(CameraCapabilities)}.
          */
         public abstract void requestCameraCapabilities();
 
         /**
          * Issues a request to the video telephony framework to retrieve the cumulative data usage for
          * the current call.  Data usage is reported back to the caller via
-         * {@link VideoCall.Listener#onCallDataUsageChanged}.
+         * {@link VideoCall.Callback#onCallDataUsageChanged}.
          */
         public abstract void requestCallDataUsage();
 
@@ -301,10 +458,9 @@
         public abstract void setPauseImage(String uri);
 
         /**
-         * Listener class which invokes callbacks after video call actions occur.
-         * @hide
+         * Callback class which invokes callbacks after video call actions occur.
          */
-        public static abstract class Listener {
+        public static abstract class Callback {
             /**
              * Called when a session modification request is received from the remote device.
              * The remote request is sent via
@@ -361,19 +517,25 @@
             public abstract void onPeerDimensionsChanged(int width, int height);
 
             /**
+             * Handles a change to the video quality.
+             *
+             * @param videoQuality  The updated peer video quality.
+             */
+            public abstract void onVideoQualityChanged(int videoQuality);
+
+            /**
              * Handles an update to the total data used for the current session.
              *
              * @param dataUsage The updated data usage.
              */
-            public abstract void onCallDataUsageChanged(int dataUsage);
+            public abstract void onCallDataUsageChanged(long dataUsage);
 
             /**
              * Handles a change in camera capabilities.
              *
              * @param cameraCapabilities The changed camera capabilities.
              */
-            public abstract void onCameraCapabilitiesChanged(
-                    CameraCapabilities cameraCapabilities);
+            public abstract void onCameraCapabilitiesChanged(CameraCapabilities cameraCapabilities);
         }
     }
 }
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index c5c3d11..1a30910 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -46,6 +46,7 @@
     private final int mCallerDisplayNamePresentation;
     private final GatewayInfo mGatewayInfo;
     private final PhoneAccountHandle mAccountHandle;
+    private final boolean mIsVideoCallProviderChanged;
     private final IVideoProvider mVideoCallProvider;
     private InCallService.VideoCall mVideoCall;
     private final String mParentCallId;
@@ -69,6 +70,7 @@
             int callerDisplayNamePresentation,
             GatewayInfo gatewayInfo,
             PhoneAccountHandle accountHandle,
+            boolean isVideoCallProviderChanged,
             IVideoProvider videoCallProvider,
             String parentCallId,
             List<String> childCallIds,
@@ -89,6 +91,7 @@
         mCallerDisplayNamePresentation = callerDisplayNamePresentation;
         mGatewayInfo = gatewayInfo;
         mAccountHandle = accountHandle;
+        mIsVideoCallProviderChanged = isVideoCallProviderChanged;
         mVideoCallProvider = videoCallProvider;
         mParentCallId = parentCallId;
         mChildCallIds = childCallIds;
@@ -232,6 +235,18 @@
         return mExtras;
     }
 
+    /**
+     * Indicates to the receiver of the {@link ParcelableCall} whether a change has occurred in the
+     * {@link android.telecom.InCallService.VideoCall} associated with this call.  Since
+     * {@link #getVideoCall()} creates a new {@link VideoCallImpl}, it is useful to know whether
+     * the provider has changed (which can influence whether it is accessed).
+     *
+     * @return {@code true} if the video call changed, {@code false} otherwise.
+     */
+    public boolean isVideoCallProviderChanged() {
+        return mIsVideoCallProviderChanged;
+    }
+
     /** Responsible for creating ParcelableCall objects for deserialized Parcels. */
     public static final Parcelable.Creator<ParcelableCall> CREATOR =
             new Parcelable.Creator<ParcelableCall> () {
@@ -252,6 +267,7 @@
             int callerDisplayNamePresentation = source.readInt();
             GatewayInfo gatewayInfo = source.readParcelable(classLoader);
             PhoneAccountHandle accountHandle = source.readParcelable(classLoader);
+            boolean isVideoCallProviderChanged = source.readByte() == 1;
             IVideoProvider videoCallProvider =
                     IVideoProvider.Stub.asInterface(source.readStrongBinder());
             String parentCallId = source.readString();
@@ -276,6 +292,7 @@
                     callerDisplayNamePresentation,
                     gatewayInfo,
                     accountHandle,
+                    isVideoCallProviderChanged,
                     videoCallProvider,
                     parentCallId,
                     childCallIds,
@@ -313,6 +330,7 @@
         destination.writeInt(mCallerDisplayNamePresentation);
         destination.writeParcelable(mGatewayInfo, 0);
         destination.writeParcelable(mAccountHandle, 0);
+        destination.writeByte((byte) (mIsVideoCallProviderChanged ? 1 : 0));
         destination.writeStrongBinder(
                 mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null);
         destination.writeString(mParentCallId);
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index dcc2713..e54e79d 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -22,6 +22,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import com.android.internal.telecom.IVideoProvider;
+
 /**
  * A parcelable representation of a conference connection.
  * @hide
@@ -32,28 +34,29 @@
     private int mState;
     private int mConnectionCapabilities;
     private List<String> mConnectionIds;
-    private long mConnectTimeMillis;
-
-    public ParcelableConference(
-            PhoneAccountHandle phoneAccount,
-            int state,
-            int connectionCapabilities,
-            List<String> connectionIds) {
-        mPhoneAccount = phoneAccount;
-        mState = state;
-        mConnectionCapabilities = connectionCapabilities;
-        mConnectionIds = connectionIds;
-        mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
-    }
+    private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
+    private final IVideoProvider mVideoProvider;
+    private final int mVideoState;
+    private StatusHints mStatusHints;
 
     public ParcelableConference(
             PhoneAccountHandle phoneAccount,
             int state,
             int connectionCapabilities,
             List<String> connectionIds,
-            long connectTimeMillis) {
-        this(phoneAccount, state, connectionCapabilities, connectionIds);
+            IVideoProvider videoProvider,
+            int videoState,
+            long connectTimeMillis,
+            StatusHints statusHints) {
+        mPhoneAccount = phoneAccount;
+        mState = state;
+        mConnectionCapabilities = connectionCapabilities;
+        mConnectionIds = connectionIds;
+        mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
+        mVideoProvider = videoProvider;
+        mVideoState = videoState;
         mConnectTimeMillis = connectTimeMillis;
+        mStatusHints = statusHints;
     }
 
     @Override
@@ -69,6 +72,10 @@
                 .append(mConnectTimeMillis)
                 .append(", children: ")
                 .append(mConnectionIds)
+                .append(", VideoState: ")
+                .append(mVideoState)
+                .append(", VideoProvider: ")
+                .append(mVideoProvider)
                 .toString();
     }
 
@@ -91,6 +98,17 @@
     public long getConnectTimeMillis() {
         return mConnectTimeMillis;
     }
+    public IVideoProvider getVideoProvider() {
+        return mVideoProvider;
+    }
+
+    public int getVideoState() {
+        return mVideoState;
+    }
+
+    public StatusHints getStatusHints() {
+        return mStatusHints;
+    }
 
     public static final Parcelable.Creator<ParcelableConference> CREATOR =
             new Parcelable.Creator<ParcelableConference> () {
@@ -103,9 +121,14 @@
             List<String> connectionIds = new ArrayList<>(2);
             source.readList(connectionIds, classLoader);
             long connectTimeMillis = source.readLong();
+            StatusHints statusHints = source.readParcelable(classLoader);
+
+            IVideoProvider videoCallProvider =
+                    IVideoProvider.Stub.asInterface(source.readStrongBinder());
+            int videoState = source.readInt();
 
             return new ParcelableConference(phoneAccount, state, capabilities, connectionIds,
-                    connectTimeMillis);
+                    videoCallProvider, videoState, connectTimeMillis, statusHints);
         }
 
         @Override
@@ -128,5 +151,9 @@
         destination.writeInt(mConnectionCapabilities);
         destination.writeList(mConnectionIds);
         destination.writeLong(mConnectTimeMillis);
+        destination.writeStrongBinder(
+                mVideoProvider != null ? mVideoProvider.asBinder() : null);
+        destination.writeInt(mVideoState);
+        destination.writeParcelable(mStatusHints, 0);
     }
 }
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 6344181..3d9acda 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -28,9 +28,11 @@
 /**
  * A unified virtual device providing a means of voice (and other) communication on a device.
  *
- * {@hide}
+ * @hide
+ * @deprecated Use {@link InCallService} directly instead of using this class.
  */
 @SystemApi
+@Deprecated
 public final class Phone {
 
     public abstract static class Listener {
@@ -104,12 +106,10 @@
 
     private boolean mCanAddCall = true;
 
-    /** {@hide} */
     Phone(InCallAdapter adapter) {
         mInCallAdapter = adapter;
     }
 
-    /** {@hide} */
     final void internalAddCall(ParcelableCall parcelableCall) {
         Call call = new Call(this, parcelableCall.getId(), mInCallAdapter);
         mCallByTelecomCallId.put(parcelableCall.getId(), call);
@@ -119,14 +119,17 @@
         fireCallAdded(call);
      }
 
-    /** {@hide} */
     final void internalRemoveCall(Call call) {
         mCallByTelecomCallId.remove(call.internalGetCallId());
         mCalls.remove(call);
+
+        InCallService.VideoCall videoCall = call.getVideoCall();
+        if (videoCall != null) {
+            videoCall.unregisterCallback();
+        }
         fireCallRemoved(call);
     }
 
-    /** {@hide} */
     final void internalUpdateCall(ParcelableCall parcelableCall) {
          Call call = mCallByTelecomCallId.get(parcelableCall.getId());
          if (call != null) {
@@ -135,7 +138,6 @@
          }
      }
 
-    /** {@hide} */
     final void internalSetPostDialWait(String telecomId, String remaining) {
         Call call = mCallByTelecomCallId.get(telecomId);
         if (call != null) {
@@ -143,7 +145,6 @@
         }
     }
 
-    /** {@hide} */
     final void internalAudioStateChanged(AudioState audioState) {
         if (!Objects.equals(mAudioState, audioState)) {
             mAudioState = audioState;
@@ -151,17 +152,14 @@
         }
     }
 
-    /** {@hide} */
     final Call internalGetCallByTelecomId(String telecomId) {
         return mCallByTelecomCallId.get(telecomId);
     }
 
-    /** {@hide} */
     final void internalBringToForeground(boolean showDialpad) {
         fireBringToForeground(showDialpad);
     }
 
-    /** {@hide} */
     final void internalSetCanAddCall(boolean canAddCall) {
         if (mCanAddCall != canAddCall) {
             mCanAddCall = canAddCall;
@@ -171,10 +169,13 @@
 
     /**
      * Called to destroy the phone and cleanup any lingering calls.
-     * @hide
      */
     final void destroy() {
         for (Call call : mCalls) {
+            InCallService.VideoCall videoCall = call.getVideoCall();
+            if (videoCall != null) {
+                videoCall.unregisterCallback();
+            }
             if (call.getState() != Call.STATE_DISCONNECTED) {
                 call.internalSetDisconnected();
             }
@@ -244,6 +245,8 @@
      * become active, and the touch screen and display will be turned off when the user's face
      * is detected to be in close proximity to the screen. This operation is a no-op on devices
      * that do not have a proximity sensor.
+     *
+     * @hide
      */
     public final void setProximitySensorOn() {
         mInCallAdapter.turnProximitySensorOn();
@@ -257,6 +260,8 @@
      * @param screenOnImmediately If true, the screen will be turned on immediately if it was
      * previously off. Otherwise, the screen will only be turned on after the proximity sensor
      * is no longer triggered.
+     *
+     * @hide
      */
     public final void setProximitySensorOff(boolean screenOnImmediately) {
         mInCallAdapter.turnProximitySensorOff(screenOnImmediately);
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index a94c2f6..bab460d 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -60,9 +60,7 @@
      * if the user has explicitly selected it to be used as the default connection manager.
      * <p>
      * See {@link #getCapabilities}
-     * @hide
      */
-    @SystemApi
     public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
 
     /**
@@ -74,9 +72,7 @@
      * <p>
      * See {@link #getCapabilities}
      * <p>
-     * {@hide}
      */
-    @SystemApi
     public static final int CAPABILITY_CALL_PROVIDER = 0x2;
 
     /**
@@ -93,9 +89,7 @@
      * Flag indicating that this {@code PhoneAccount} is capable of placing video calls.
      * <p>
      * See {@link #getCapabilities}
-     * @hide
      */
-    @SystemApi
     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
 
     /**
@@ -205,13 +199,6 @@
             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
         }
 
-        /** @hide */
-        @SystemApi
-        public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
-            mAccountHandle = accountHandle;
-            return this;
-        }
-
         /**
          * Sets the address. See {@link PhoneAccount#getAddress}.
          *
@@ -335,9 +322,7 @@
          *
          * @param uriScheme The URI scheme.
          * @return The builder.
-         * @hide
          */
-        @SystemApi
         public Builder addSupportedUriScheme(String uriScheme) {
             if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
                 this.mSupportedUriSchemes.add(uriScheme);
@@ -426,9 +411,7 @@
      * Returns a builder initialized with the current {@link PhoneAccount} instance.
      *
      * @return The builder.
-     * @hide
      */
-    @SystemApi
     public Builder toBuilder() { return new Builder(this); }
 
     /**
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 4600b72..60917b2 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -47,8 +46,6 @@
         this(componentName, id, Process.myUserHandle());
     }
 
-    /** @hide */
-    @SystemApi
     public PhoneAccountHandle(
             ComponentName componentName,
             String id,
@@ -91,9 +88,7 @@
 
     /**
      * @return the {@link UserHandle} to use when connecting to this PhoneAccount.
-     * @hide
      */
-    @SystemApi
     public UserHandle getUserHandle() {
         return mUserHandle;
     }
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index a8879ae..fba3ee3 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -18,7 +18,6 @@
 
 import com.android.internal.telecom.IConnectionService;
 
-import android.annotation.SystemApi;
 import android.os.RemoteException;
 
 import java.util.ArrayList;
@@ -30,9 +29,7 @@
 
 /**
  * Represents a conference call which can contain any number of {@link Connection} objects.
- * @hide
  */
-@SystemApi
 public final class RemoteConference {
 
     public abstract static class Callback {
@@ -164,11 +161,6 @@
         return mState;
     }
 
-    /** @hide */
-    @Deprecated public final int getCallCapabilities() {
-        return getConnectionCapabilities();
-    }
-
     public final int getConnectionCapabilities() {
         return mConnectionCapabilities;
     }
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 486691f..4ecfd50 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -20,7 +20,6 @@
 import com.android.internal.telecom.IVideoCallback;
 import com.android.internal.telecom.IVideoProvider;
 
-import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -38,9 +37,7 @@
  *
  * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
  * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest)
- * @hide
  */
-@SystemApi
 public final class RemoteConnection {
 
     public static abstract class Callback {
@@ -73,11 +70,6 @@
          */
         public void onRingbackRequested(RemoteConnection connection, boolean ringback) {}
 
-        /** @hide */
-        @Deprecated public void onCallCapabilitiesChanged(
-                RemoteConnection connection,
-                int callCapabilities) {}
-
         /**
          * Indicates that the call capabilities of this {@code RemoteConnection} have changed.
          * See {@link #getConnectionCapabilities()}.
@@ -223,11 +215,13 @@
 
             public void onPeerDimensionsChanged(VideoProvider videoProvider, int width, int height) {}
 
-            public void onCallDataUsageChanged(VideoProvider videoProvider, int dataUsage) {}
+            public void onCallDataUsageChanged(VideoProvider videoProvider, long dataUsage) {}
 
             public void onCameraCapabilitiesChanged(
                     VideoProvider videoProvider,
                     CameraCapabilities cameraCapabilities) {}
+
+            public void onVideoQualityChanged(VideoProvider videoProvider, int videoQuality) {}
         }
 
         private final IVideoCallback mVideoCallbackDelegate = new IVideoCallback() {
@@ -265,7 +259,7 @@
             }
 
             @Override
-            public void changeCallDataUsage(int dataUsage) {
+            public void changeCallDataUsage(long dataUsage) {
                 for (Listener l : mListeners) {
                     l.onCallDataUsageChanged(VideoProvider.this, dataUsage);
                 }
@@ -279,6 +273,13 @@
             }
 
             @Override
+            public void changeVideoQuality(int videoQuality) {
+                for (Listener l : mListeners) {
+                    l.onVideoQualityChanged(VideoProvider.this, videoQuality);
+                }
+            }
+
+            @Override
             public IBinder asBinder() {
                 return null;
             }
@@ -300,7 +301,7 @@
         public VideoProvider(IVideoProvider videoProviderBinder) {
             mVideoProviderBinder = videoProviderBinder;
             try {
-                mVideoProviderBinder.setVideoCallback(mVideoCallbackServant.getStub().asBinder());
+                mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder());
             } catch (RemoteException e) {
             }
         }
@@ -584,7 +585,6 @@
 
     /**
      * Obtains the video provider of this {@code RemoteConnection}.
-     *
      * @return The video provider associated with this {@code RemoteConnection}.
      * @hide
      */
@@ -842,7 +842,6 @@
         mConnectionCapabilities = connectionCapabilities;
         for (Callback c : mCallbacks) {
             c.onConnectionCapabilitiesChanged(this, connectionCapabilities);
-            c.onCallCapabilitiesChanged(this, connectionCapabilities);
         }
     }
 
diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java
index dd3a639..a32eae7 100644
--- a/telecomm/java/android/telecom/StatusHints.java
+++ b/telecomm/java/android/telecom/StatusHints.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -30,9 +29,7 @@
 
 /**
  * Contains status label and icon displayed in the in-call UI.
- * @hide
  */
-@SystemApi
 public final class StatusHints implements Parcelable {
 
     private final ComponentName mPackageName;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8be3e66..2ea84be 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -55,8 +55,6 @@
      * Input: get*Extra field {@link #EXTRA_PHONE_ACCOUNT_HANDLE} contains the component name of the
      * {@link android.telecom.ConnectionService} that Telecom should bind to. Telecom will then
      * ask the connection service for more information about the call prior to showing any UI.
-     *
-     * @hide
      */
     public static final String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
 
@@ -85,9 +83,7 @@
     /**
      * The {@link android.content.Intent} action used to show the settings page used to configure
      * {@link PhoneAccount} preferences.
-     * @hide
      */
-    @SystemApi
     public static final String ACTION_CHANGE_PHONE_ACCOUNTS =
             "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
 
@@ -133,10 +129,7 @@
      * Optional extra for {@link #ACTION_INCOMING_CALL} containing a {@link Bundle} which contains
      * metadata about the call. This {@link Bundle} will be returned to the
      * {@link ConnectionService}.
-     *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_INCOMING_CALL_EXTRAS =
             "android.telecom.extra.INCOMING_CALL_EXTRAS";
 
@@ -209,9 +202,7 @@
      * {@link ConnectionService}s which interact with {@link RemoteConnection}s should only populate
      * this if the {@link android.telephony.TelephonyManager#getLine1Number()} value, as that is the
      * user's expected caller ID.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
 
     /**
@@ -352,9 +343,7 @@
      * @param uriScheme The URI scheme.
      * @return The {@link PhoneAccountHandle} corresponding to the user-chosen default for outgoing
      * phone calls for a specified URI scheme.
-     * @hide
      */
-    @SystemApi
     public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
         try {
             if (isServiceConnected()) {
@@ -407,7 +396,6 @@
      * {@code null}, indicating that there currently exists no user-chosen default
      * {@code PhoneAccount}.
      * @return The phone account handle of the current sim call manager.
-     * @hide
      */
     public PhoneAccountHandle getSimCallManager() {
         try {
@@ -506,8 +494,6 @@
      *
      * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @return A list of {@code PhoneAccountHandle} objects.
-     *
-     * @hide
      */
     public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
         try {
@@ -521,19 +507,6 @@
     }
 
     /**
-     * Determine whether the device has more than one account registered that can make and receive
-     * phone calls.
-     *
-     * @return {@code true} if the device has more than one account registered and {@code false}
-     * otherwise.
-     * @hide
-     */
-    @SystemApi
-    public boolean hasMultipleCallCapableAccounts() {
-        return getCallCapablePhoneAccounts().size() > 1;
-    }
-
-    /**
      *  Returns a list of all {@link PhoneAccount}s registered for the calling package.
      *
      * @return A list of {@code PhoneAccountHandle} objects.
@@ -636,10 +609,7 @@
      * {@link PhoneAccountHandle#getComponentName()} does not match the package name of the app.
      *
      * @param account The complete {@link PhoneAccount}.
-     *
-     * @hide
      */
-    @SystemApi
     public void registerPhoneAccount(PhoneAccount account) {
         try {
             if (isServiceConnected()) {
@@ -654,9 +624,7 @@
      * Remove a {@link PhoneAccount} registration from the system.
      *
      * @param accountHandle A {@link PhoneAccountHandle} for the {@link PhoneAccount} to unregister.
-     * @hide
      */
-    @SystemApi
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
@@ -672,6 +640,15 @@
      * @hide
      */
     @SystemApi
+    public void clearPhoneAccounts() {
+        clearAccounts();
+    }
+    /**
+     * Remove all Accounts that belong to the calling package from the system.
+     * @deprecated Use {@link #clearPhoneAccounts()} instead.
+     * @hide
+     */
+    @SystemApi
     public void clearAccounts() {
         try {
             if (isServiceConnected()) {
@@ -717,10 +694,7 @@
      *
      * @param accountHandle The handle for the account to check the voicemail number against
      * @param number The number to look up.
-     *
-     * @hide
      */
-    @SystemApi
     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
         try {
             if (isServiceConnected()) {
@@ -733,23 +707,21 @@
     }
 
     /**
-     * Return whether a given phone account has a voicemail number configured.
+     * Return the voicemail number for a given phone account.
      *
-     * @param accountHandle The handle for the account to check for a voicemail number.
-     * @return {@code true} If the given phone account has a voicemail number.
-     *
-     * @hide
+     * @param accountHandle The handle for the phone account.
+     * @return The voicemail number for the phone account, and {@code null} if one has not been
+     *         configured.
      */
-    @SystemApi
-    public boolean hasVoiceMailNumber(PhoneAccountHandle accountHandle) {
+    public String getVoiceMailNumber(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().hasVoiceMailNumber(accountHandle);
+                return getTelecomService().getVoiceMailNumber(accountHandle);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
         }
-        return false;
+        return null;
     }
 
     /**
@@ -757,10 +729,7 @@
      *
      * @param accountHandle The handle for the account retrieve a number for.
      * @return A string representation of the line 1 phone number.
-     *
-     * @hide
      */
-    @SystemApi
     public String getLine1Number(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
@@ -870,10 +839,7 @@
 
     /**
      * Silences the ringer if a ringing call exists.
-     *
-     * @hide
      */
-    @SystemApi
     public void silenceRinger() {
         try {
             if (isServiceConnected()) {
@@ -934,9 +900,7 @@
      *            {@link #registerPhoneAccount}.
      * @param extras A bundle that will be passed through to
      *            {@link ConnectionService#onCreateIncomingConnection}.
-     * @hide
      */
-    @SystemApi
     public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
         try {
             if (isServiceConnected()) {
@@ -1006,10 +970,8 @@
      * @param accountHandle The handle for the account the MMI code should apply to.
      * @param dialString The digits to dial.
      * @return True if the digits were processed as an MMI code, false otherwise.
-     * @hide
      */
-    @SystemApi
-    public boolean handleMmi(PhoneAccountHandle accountHandle, String dialString) {
+    public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) {
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
@@ -1026,9 +988,7 @@
      * {@code null} to return a URI which will use the default account.
      * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
      * for the the content retrieve.
-     * @hide
      */
-    @SystemApi
     public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
         ITelecomService service = getTelecomService();
         if (service != null && accountHandle != null) {
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 925058e..3779d1a 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -42,10 +42,11 @@
     private static final int MSG_CHANGE_PEER_DIMENSIONS = 4;
     private static final int MSG_CHANGE_CALL_DATA_USAGE = 5;
     private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 6;
+    private static final int MSG_CHANGE_VIDEO_QUALITY = 7;
 
     private final IVideoProvider mVideoProvider;
     private final VideoCallListenerBinder mBinder;
-    private VideoCall.Listener mVideoCallListener;
+    private VideoCall.Callback mCallback;
 
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
@@ -88,7 +89,12 @@
         }
 
         @Override
-        public void changeCallDataUsage(int dataUsage) {
+        public void changeVideoQuality(int videoQuality) {
+            mHandler.obtainMessage(MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0).sendToTarget();
+        }
+
+        @Override
+        public void changeCallDataUsage(long dataUsage) {
             mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, dataUsage).sendToTarget();
         }
 
@@ -103,14 +109,14 @@
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
-            if (mVideoCallListener == null) {
+            if (mCallback == null) {
                 return;
             }
 
             SomeArgs args;
             switch (msg.what) {
                 case MSG_RECEIVE_SESSION_MODIFY_REQUEST:
-                    mVideoCallListener.onSessionModifyRequestReceived((VideoProfile) msg.obj);
+                    mCallback.onSessionModifyRequestReceived((VideoProfile) msg.obj);
                     break;
                 case MSG_RECEIVE_SESSION_MODIFY_RESPONSE:
                     args = (SomeArgs) msg.obj;
@@ -119,32 +125,35 @@
                         VideoProfile requestProfile = (VideoProfile) args.arg2;
                         VideoProfile responseProfile = (VideoProfile) args.arg3;
 
-                        mVideoCallListener.onSessionModifyResponseReceived(
+                        mCallback.onSessionModifyResponseReceived(
                                 status, requestProfile, responseProfile);
                     } finally {
                         args.recycle();
                     }
                     break;
                 case MSG_HANDLE_CALL_SESSION_EVENT:
-                    mVideoCallListener.onCallSessionEvent((int) msg.obj);
+                    mCallback.onCallSessionEvent((int) msg.obj);
                     break;
                 case MSG_CHANGE_PEER_DIMENSIONS:
                     args = (SomeArgs) msg.obj;
                     try {
                         int width = (int) args.arg1;
                         int height = (int) args.arg2;
-                        mVideoCallListener.onPeerDimensionsChanged(width, height);
+                        mCallback.onPeerDimensionsChanged(width, height);
                     } finally {
                         args.recycle();
                     }
                     break;
                 case MSG_CHANGE_CALL_DATA_USAGE:
-                    mVideoCallListener.onCallDataUsageChanged(msg.arg1);
+                    mCallback.onCallDataUsageChanged((long) msg.obj);
                     break;
                 case MSG_CHANGE_CAMERA_CAPABILITIES:
-                    mVideoCallListener.onCameraCapabilitiesChanged(
+                    mCallback.onCameraCapabilitiesChanged(
                             (CameraCapabilities) msg.obj);
                     break;
+                case MSG_CHANGE_VIDEO_QUALITY:
+                    mCallback.onVideoQualityChanged(msg.arg1);
+                    break;
                 default:
                     break;
             }
@@ -157,12 +166,21 @@
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
 
         mBinder = new VideoCallListenerBinder();
-        mVideoProvider.setVideoCallback(mBinder);
+        mVideoProvider.addVideoCallback(mBinder);
     }
 
     /** {@inheritDoc} */
-    public void setVideoCallListener(VideoCall.Listener videoCallListener) {
-        mVideoCallListener = videoCallListener;
+    public void registerCallback(VideoCall.Callback callback) {
+        mCallback = callback;
+    }
+
+    /** {@inheritDoc} */
+    public void unregisterCallback() {
+        mCallback = null;
+        try {
+            mVideoProvider.removeVideoCallback(mBinder);
+        } catch (RemoteException e) {
+        }
     }
 
     /** {@inheritDoc} */
@@ -244,4 +262,4 @@
         } catch (RemoteException e) {
         }
     }
-}
\ No newline at end of file
+}
diff --git a/telecomm/java/android/telecom/VideoCallbackServant.java b/telecomm/java/android/telecom/VideoCallbackServant.java
index d0e3f22..1123621 100644
--- a/telecomm/java/android/telecom/VideoCallbackServant.java
+++ b/telecomm/java/android/telecom/VideoCallbackServant.java
@@ -38,6 +38,7 @@
     private static final int MSG_CHANGE_PEER_DIMENSIONS = 3;
     private static final int MSG_CHANGE_CALL_DATA_USAGE = 4;
     private static final int MSG_CHANGE_CAMERA_CAPABILITIES = 5;
+    private static final int MSG_CHANGE_VIDEO_QUALITY = 6;
 
     private final IVideoCallback mDelegate;
 
@@ -90,7 +91,7 @@
                 case MSG_CHANGE_CALL_DATA_USAGE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        mDelegate.changeCallDataUsage(args.argi1);
+                        mDelegate.changeCallDataUsage((long) args.arg1);
                     } finally {
                         args.recycle();
                     }
@@ -100,6 +101,10 @@
                     mDelegate.changeCameraCapabilities((CameraCapabilities) msg.obj);
                     break;
                 }
+                case MSG_CHANGE_VIDEO_QUALITY: {
+                    mDelegate.changeVideoQuality(msg.arg1);
+                    break;
+                }
             }
         }
     };
@@ -136,9 +141,9 @@
         }
 
         @Override
-        public void changeCallDataUsage(int dataUsage) throws RemoteException {
+        public void changeCallDataUsage(long dataUsage) throws RemoteException {
             SomeArgs args = SomeArgs.obtain();
-            args.argi1 = dataUsage;
+            args.arg1 = dataUsage;
             mHandler.obtainMessage(MSG_CHANGE_CALL_DATA_USAGE, args).sendToTarget();
         }
 
@@ -148,6 +153,11 @@
             mHandler.obtainMessage(MSG_CHANGE_CAMERA_CAPABILITIES, cameraCapabilities)
                     .sendToTarget();
         }
+
+        @Override
+        public void changeVideoQuality(int videoQuality) throws RemoteException {
+            mHandler.obtainMessage(MSG_CHANGE_VIDEO_QUALITY, videoQuality, 0).sendToTarget();
+        }
     };
 
     public VideoCallbackServant(IVideoCallback delegate) {
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index e62e994..2fd438a 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -24,6 +24,11 @@
  */
 public class VideoProfile implements Parcelable {
     /**
+     * "Unknown" video quality.
+     * @hide
+     */
+    public static final int QUALITY_UNKNOWN = 0;
+    /**
      * "High" video quality.
      */
     public static final int QUALITY_HIGH = 1;
@@ -179,6 +184,17 @@
         }
 
         /**
+         * Whether the video state is any of the video type
+         * @param videoState The video state.
+         * @hide
+         * @return Returns true if the video state TX or RX or Bidirectional
+         */
+        public static boolean isVideo(int videoState) {
+            return hasState(videoState, TX_ENABLED) || hasState(videoState, RX_ENABLED)
+                    || hasState(videoState, BIDIRECTIONAL);
+        }
+
+        /**
          * Whether the video transmission is enabled.
          * @param videoState The video state.
          * @return Returns true if the video transmission is enabled.
diff --git a/telecomm/java/android/telecom/Voicemail.java b/telecomm/java/android/telecom/Voicemail.java
index 864c6b1..dbec2ad 100644
--- a/telecomm/java/android/telecom/Voicemail.java
+++ b/telecomm/java/android/telecom/Voicemail.java
@@ -22,6 +22,8 @@
 
 /**
  * Represents a single voicemail stored in the voicemail content provider.
+ *
+ * @hide
  */
 public class Voicemail implements Parcelable {
     private final Long mTimestamp;
@@ -263,4 +265,4 @@
         mIsRead = in.readInt() > 0 ? true : false;
         mHasContent = in.readInt() > 0 ? true : false;
     }
-}
\ No newline at end of file
+}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index d2030f2..35db97f 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -121,9 +121,9 @@
     boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number);
 
     /**
-     * @see TelecomServiceImpl#hasVoiceMailNumber
+     * @see TelecomServiceImpl#getVoiceMailNumber
      */
-    boolean hasVoiceMailNumber(in PhoneAccountHandle accountHandle);
+    String getVoiceMailNumber(in PhoneAccountHandle accountHandle);
 
     /**
      * @see TelecomServiceImpl#getLine1Number
diff --git a/telecomm/java/com/android/internal/telecom/IVideoCallback.aidl b/telecomm/java/com/android/internal/telecom/IVideoCallback.aidl
index f758b60..59f8f0c 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoCallback.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoCallback.aidl
@@ -39,7 +39,9 @@
 
     void changePeerDimensions(int width, int height);
 
-    void changeCallDataUsage(int dataUsage);
+    void changeCallDataUsage(long dataUsage);
 
     void changeCameraCapabilities(in CameraCapabilities cameraCapabilities);
+
+    void changeVideoQuality(int videoQuality);
 }
diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
index e96d9d3..bff3865 100644
--- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
+++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl
@@ -25,7 +25,9 @@
  * @hide
  */
 oneway interface IVideoProvider {
-    void setVideoCallback(IBinder videoCallbackBinder);
+    void addVideoCallback(IBinder videoCallbackBinder);
+
+    void removeVideoCallback(IBinder videoCallbackBinder);
 
     void setCamera(String cameraId);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
new file mode 100644
index 0000000..b6f6888
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2015 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 com.android.internal.telephony.ICarrierConfigLoader;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Provides access to telephony configuration values that are carrier-specific.
+ * <p>
+ * Users should obtain an instance of this class by calling
+ * {@code mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);}
+ * </p>
+ *
+ * @see Context#getSystemService
+ * @see Context#CARRIER_CONFIG_SERVICE
+ */
+public class CarrierConfigManager {
+
+    /**
+     * This intent is broadcast by the system when carrier config changes.
+     */
+    public static final String
+            ACTION_CARRIER_CONFIG_CHANGED = "android.intent.action.carrier_config_changed";
+
+    /**
+     * Flag specifying whether VoLTE should be available for carrier, independent of carrier
+     * provisioning. If false: hard disabled. If true: then depends on carrier provisioning,
+     * availability, etc.
+     */
+    public static final String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
+
+    /**
+     * Flag specifying whether VoLTE availability is based on provisioning.
+     */
+    public static final String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
+
+    /**
+     * Flag specifying whether VoLTE TTY is supported.
+     */
+    public static final String BOOL_CARRIER_VOLTE_TTY_SUPPORTED
+            = "bool_carrier_volte_tty_supported";
+
+    /**
+     * Show APN Settings for some CDMA carriers.
+     */
+    public static final String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+
+    /**
+     * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
+     * this is the value that should be used instead. A configuration value of
+     * RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
+     * assumption for phone type (GSM) should be used.
+     */
+    public static final String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
+
+    /* The following 3 fields are related to carrier visual voicemail. */
+
+    /**
+     *  The carrier number MO sms messages are sent to.
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final String STRING_VVM_DESTINATION_NUMBER = "string_vvm_destination_number";
+
+    /**
+     * The port through which the MO sms messages are sent through.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String SHORT_VVM_PORT_NUMBER = "string_vvm_port_number";
+
+    /**
+     * The type of visual voicemail protocol the carrier adheres to (see below).
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String STRING_VVM_TYPE = "string_vvm_type";
+
+    /* Visual voicemail protocols */
+
+    /**
+     * The OMTP protocol.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String VVM_TYPE_OMTP = "vvm_type_omtp";
+
+    private final static String TAG = "CarrierConfigManager";
+
+    /** The default value for every variable. */
+    private final static Bundle sDefaults;
+
+    static {
+        sDefaults = new Bundle();
+        sDefaults.putBoolean(BOOL_CARRIER_VOLTE_AVAILABLE, false);
+        sDefaults.putBoolean(BOOL_CARRIER_VOLTE_PROVISIONED, false);
+        sDefaults.putBoolean(BOOL_CARRIER_VOLTE_TTY_SUPPORTED, true);
+        sDefaults.putBoolean(BOOL_SHOW_APN_SETTING_CDMA, false);
+
+        sDefaults.putInt(INT_VOLTE_REPLACEMENT_RAT, 0);
+    }
+
+    /**
+     * Gets the configuration values for a particular subscription, which is associated with a
+     * specific SIM card. If an invalid subId is used, the returned config will contain default
+     * values.
+     *
+     * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+     * @return A {@link Bundle} containing the config for the given subId, or default values for an
+     *         invalid subId.
+     */
+    public Bundle getConfigForSubId(int subId) {
+        try {
+            return getICarrierConfigLoader().getConfigForSubId(subId);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "Error getting config for subId " + Integer.toString(subId) + ": "
+                    + ex.toString());
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "Error getting config for subId " + Integer.toString(subId) + ": "
+                    + ex.toString());
+        }
+        return null;
+    }
+
+    /**
+     * Gets the configuration values for the default subscription.
+     *
+     * @see #getConfigForSubId
+     */
+    public Bundle getConfig() {
+        return getConfigForSubId(SubscriptionManager.getDefaultSubId());
+    }
+
+    /**
+     * Calling this method triggers telephony services to fetch the current carrier configuration.
+     * <p>
+     * Normally this does not need to be called because the platform reloads config on its own. Call
+     * this method if your app wants to update config at an arbitrary moment.
+     * </p>
+     * <p>
+     * This method returns before the reload has completed, and
+     * {@link android.service.carrier.CarrierConfigService#onLoadConfig} will be called from an
+     * arbitrary thread.
+     * </p>
+     */
+    public void reloadCarrierConfigForSubId(int subId) {
+        try {
+            getICarrierConfigLoader().reloadCarrierConfigForSubId(subId);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex.toString());
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex.toString());
+        }
+    }
+
+    /**
+     * Request the carrier config loader to update the cofig for phoneId.
+     *
+     * Depending on simState, the config may be cleared or loaded from config app.
+     * This is only used by SubscriptionInfoUpdater.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void updateConfigForPhoneId(int phoneId, String simState) {
+        try {
+            getICarrierConfigLoader().updateConfigForPhoneId(phoneId, simState);
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex.toString());
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex.toString());
+        }
+    }
+
+    /**
+     * Returns a bundle with the default value for every supported configuration variable.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static Bundle getDefaultConfig() {
+        return sDefaults;
+    }
+
+    /** @hide */
+    private ICarrierConfigLoader getICarrierConfigLoader() {
+        return ICarrierConfigLoader.Stub
+                .asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
+    }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index aca94e9..88ca8a4 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1133,5 +1133,19 @@
         logd("getSimStateForSubscriber: simState=" + simState + " subId=" + subId);
         return simState;
     }
+
+    /**
+     * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
+     * and the SIM providing the subscription is present in a slot and in "LOADED" state.
+     * @hide
+     */
+    public boolean isActiveSubId(int subId) {
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            return iSub.isActiveSubId(subId);
+        } catch (RemoteException ex) {
+        }
+        return false;
+    }
 }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e1a3de7..d0a1dc2 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -162,7 +162,6 @@
      * Returns 1 for Single standby mode (Single SIM functionality)
      * Returns 2 for Dual standby mode.(Dual SIM functionality)
      */
-    /** {@hide} */
     public int getPhoneCount() {
         int phoneCount = 1;
         switch (getMultiSimConfiguration()) {
@@ -639,7 +638,6 @@
      *
      * @param slotId of which deviceID is returned
      */
-    /** {@hide} */
     public String getDeviceId(int slotId) {
         // FIXME this assumes phoneId == slotId
         try {
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 8740e19..604d32d 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -270,7 +270,6 @@
         return "{ serviceType=" + mServiceType +
                 ", callType=" + mCallType +
                 ", restrictCause=" + mRestrictCause +
-                ", callExtras=" + mCallExtras.toString() +
                 ", mediaProfile=" + mMediaProfile.toString() + " }";
     }
 
@@ -313,22 +312,31 @@
      * @param callType The call type.
      * @return The video state.
      */
-    public static int getVideoStateFromCallType(int callType) {
-        switch (callType) {
-            case CALL_TYPE_VT_NODIR:
-                return VideoProfile.VideoState.PAUSED |
-                        VideoProfile.VideoState.BIDIRECTIONAL;
+    public static int getVideoStateFromImsCallProfile(ImsCallProfile callProfile) {
+        int videostate = VideoProfile.VideoState.AUDIO_ONLY;
+        switch (callProfile.mCallType) {
             case CALL_TYPE_VT_TX:
-                return VideoProfile.VideoState.TX_ENABLED;
+                videostate = VideoProfile.VideoState.TX_ENABLED;
+                break;
             case CALL_TYPE_VT_RX:
-                return VideoProfile.VideoState.RX_ENABLED;
+                videostate = VideoProfile.VideoState.RX_ENABLED;
+                break;
             case CALL_TYPE_VT:
-                return VideoProfile.VideoState.BIDIRECTIONAL;
+                videostate = VideoProfile.VideoState.BIDIRECTIONAL;
+                break;
             case CALL_TYPE_VOICE:
-                return VideoProfile.VideoState.AUDIO_ONLY;
+                videostate = VideoProfile.VideoState.AUDIO_ONLY;
+                break;
             default:
-                return VideoProfile.VideoState.AUDIO_ONLY;
+                videostate = VideoProfile.VideoState.AUDIO_ONLY;
+                break;
         }
+        if (callProfile.isVideoPaused() && videostate != VideoProfile.VideoState.AUDIO_ONLY) {
+            videostate |= VideoProfile.VideoState.PAUSED;
+        } else {
+            videostate &= ~VideoProfile.VideoState.PAUSED;
+        }
+        return videostate;
     }
 
     /**
@@ -387,6 +395,14 @@
     }
 
     /**
+     * Checks if video call is paused
+     * @return true if call is video paused
+     */
+    public boolean isVideoPaused() {
+        return mMediaProfile.mVideoDirection == ImsStreamMediaProfile.DIRECTION_INACTIVE;
+    }
+
+    /**
      * Determines if a video state is set in a video state bit-mask.
      *
      * @param videoState The video state bit mask.
diff --git a/telephony/java/com/android/ims/ImsConfigListener.aidl b/telephony/java/com/android/ims/ImsConfigListener.aidl
index e827774..64a5015 100644
--- a/telephony/java/com/android/ims/ImsConfigListener.aidl
+++ b/telephony/java/com/android/ims/ImsConfigListener.aidl
@@ -48,4 +48,26 @@
      * @return void.
      */
     void onSetFeatureResponse(int feature, int network, int value, int status);
-}
\ No newline at end of file
+
+    /**
+     * Notifies client the value of the get operation result on the video quality item.
+     *
+     * @param status. as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+     * @param quality. as defined in com.android.ims.ImsConfig#OperationValuesConstants.
+     * @return void
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+     void onGetVideoQuality(int status, int quality);
+
+    /**
+     * Notifies client the set value operation result for video quality item.
+     * Used by clients that need to be notified the set operation result.
+     *
+     * @param status. as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+     * @return void
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+     void onSetVideoQuality(int status);
+}
diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
index 84d1c545..0443c3e 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -115,4 +115,12 @@
      * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
      */
     void callSessionTtyModeReceived(in IImsCallSession session, in int mode);
+
+    /**
+     * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+     *
+     * @param session The call session.
+     * @param isMultiParty {@code true} if the session became multiparty, {@code false} otherwise.
+     */
+    void callSessionMultipartyStateChanged(in IImsCallSession session, in boolean isMultiParty);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl
index 441e03e..7324814 100644
--- a/telephony/java/com/android/ims/internal/IImsConfig.aidl
+++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl
@@ -100,4 +100,24 @@
      * @return void
      */
     boolean getVolteProvisioned();
+
+    /**
+     *
+     * Gets the value for ims fature item video quality.
+     *
+     * @param listener. Video quality value returned asynchronously through listener.
+     * @return void
+     */
+    oneway void getVideoQuality(ImsConfigListener listener);
+
+    /**
+     * Sets the value for IMS feature item video quality.
+     *
+     * @param quality, defines the value of video quality.
+     * @param listener, provided if caller needs to be notified for set result.
+     * @return void
+     *
+     * @throws ImsException if calling the IMS service results in an error.
+     */
+     oneway void setVideoQuality(int quality, ImsConfigListener listener);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl b/telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl
index f867fcb..be8751b 100644
--- a/telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl
+++ b/telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl
@@ -41,7 +41,9 @@
 
     void changePeerDimensions(int width, int height);
 
-    void changeCallDataUsage(int dataUsage);
+    void changeCallDataUsage(long dataUsage);
 
     void changeCameraCapabilities(in CameraCapabilities cameraCapabilities);
+
+    void changeVideoQuality(int videoQuality);
 }
diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
new file mode 100644
index 0000000..b5cdd9a2
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to interact with the CarrierConfigLoader
+ */
+interface ICarrierConfigLoader {
+
+    Bundle getConfigForSubId(int subId);
+
+    void reloadCarrierConfigForSubId(int subId);
+
+    void updateConfigForPhoneId(int phoneId, String simState);
+}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index acbc0aa..c12137d 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -171,4 +171,5 @@
      */
     int getSimStateForSubscriber(int subId);
 
+    boolean isActiveSubId(int subId);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index b8e8064..0ebd719 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -186,4 +186,11 @@
 
     //FIXME maybe this shouldn't be here - sprout only
     public static final int CAPABILITY_3G   = 1;
+
+    /**
+     * Values for the adb property "persist.radio.videocall.audio.output"
+     */
+    public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0;
+    public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1;
+    public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER;
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 082e8bb..12541d8 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -69,6 +69,14 @@
     int SS_MODIFIED_TO_USSD = 25;             /* SS request modified to USSD */
     int SUBSCRIPTION_NOT_SUPPORTED = 26;      /* Subscription not supported */
     int SS_MODIFIED_TO_SS = 27;               /* SS request modified to different SS request */
+    int SIM_ALREADY_POWERED_OFF = 29;         /* SAP: 0x03, Error card aleready powered off */
+    int SIM_ALREADY_POWERED_ON = 30;          /* SAP: 0x05, Error card already powered on */
+    int SIM_DATA_NOT_AVAILABLE = 31;          /* SAP: 0x06, Error data not available */
+    int SIM_SAP_CONNECT_FAILURE = 32;
+    int SIM_SAP_MSG_SIZE_TOO_LARGE = 33;
+    int SIM_SAP_MSG_SIZE_TOO_SMALL = 34;
+    int SIM_SAP_CONNECT_OK_CALL_ONGOING = 35;
+    int LCE_NOT_SUPPORTED = 36;               /* Link Capacity Estimation (LCE) not supported */
 
 
     /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
@@ -135,6 +143,11 @@
     int NV_CONFIG_ERASE_RESET = 2;
     int NV_CONFIG_FACTORY_RESET = 3;
 
+    /* LCE service related constants. */
+    int LCE_NOT_AVAILABLE = -1;
+    int LCE_STOPPED = 0;
+    int LCE_ACTIVE = 1;
+
 /*
 cat include/telephony/ril.h | \
    egrep '^#define' | \
@@ -307,6 +320,9 @@
     int RIL_REQUEST_SHUTDOWN = 129;
     int RIL_REQUEST_GET_RADIO_CAPABILITY = 130;
     int RIL_REQUEST_SET_RADIO_CAPABILITY = 131;
+    int RIL_REQUEST_START_LCE = 132;
+    int RIL_REQUEST_STOP_LCE = 133;
+    int RIL_REQUEST_PULL_LCEDATA = 134;
 
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
@@ -354,4 +370,5 @@
     int RIL_UNSOL_RADIO_CAPABILITY = 1042;
     int RIL_UNSOL_ON_SS = 1043;
     int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
+    int RIL_UNSOL_LCEDATA_RECV = 1045;
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 92cd468..26faaba 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -319,6 +319,7 @@
     public static final String EXTRA_PLMN       = "plmn";
     public static final String EXTRA_SHOW_SPN   = "showSpn";
     public static final String EXTRA_SPN        = "spn";
+    public static final String EXTRA_DATA_SPN   = "spnData";
 
     /**
      * <p>Broadcast Action: It indicates one column of a subinfo record has been changed
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index c89208d..645c3a1 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -209,4 +209,12 @@
      * Set to the sim count.
      */
     static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count";
+
+    /**
+     * Controls audio route for video calls.
+     * 0 - Use the default audio routing strategy.
+     * 1 - Disable the speaker. Route the audio to Headset or Bluetooth
+     *     or Earpiece, based on the default audio routing strategy.
+     */
+    static final String PROPERTY_VIDEOCALL_AUDIO_OUTPUT = "persist.radio.call.audio.output";
 }
diff --git a/tools/layoutlib/.idea/libraries/guava.xml b/tools/layoutlib/.idea/libraries/guava.xml
index d47fc06..eb60719 100644
--- a/tools/layoutlib/.idea/libraries/guava.xml
+++ b/tools/layoutlib/.idea/libraries/guava.xml
@@ -1,11 +1,11 @@
 <component name="libraryTable">
   <library name="guava">
     <CLASSES>
-      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar!/" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
-      <root url="file://$PROJECT_DIR$/../../../../external/guava/guava/src" />
+      <root url="jar://$PROJECT_DIR$/../../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0-sources.jar!/" />
     </SOURCES>
   </library>
 </component>
\ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
index d97d82c..0b22717 100644
--- a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
+++ b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
@@ -2,8 +2,8 @@
   <configuration default="false" name="All in bridge" type="JUnit" factoryName="JUnit" singleton="true">
     <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
     <module name="bridge" />
-    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-    <option name="ALTERNATIVE_JRE_PATH" value="1.7" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+    <option name="ALTERNATIVE_JRE_PATH" value="" />
     <option name="PACKAGE_NAME" value="" />
     <option name="MAIN_CLASS_NAME" value="" />
     <option name="METHOD_NAME" value="" />
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
index 491dee8..0f37fce 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
@@ -34,6 +34,10 @@
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
     }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_6
+        targetCompatibility JavaVersion.VERSION_1_6
+    }
 }
 
 dependencies {
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class
new file mode 100644
index 0000000..1ca7e01
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
index e29e490..ceb56bf 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
index 4ae0da7..c363055 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
index 6729eb4..edda3de 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
index 985d267..d252462 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/MyActivity.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class
index 5142ca6..9bab801 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$attr.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
index cb52ba5..7ad8605 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$dimen.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
index 5290cf6..e9e0a33 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$drawable.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
index 49b1df6..d109302 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$id.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
index 85b2029..816ecc8 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
index 428fdf4..b034b75 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$menu.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
index 027d5d3..f86b1d3 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$string.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
index c7d64f8..8bbae90 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$style.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
index 8831b71..8af745d 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
index e13ad72..d7e5486 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
@@ -56,7 +56,7 @@
 
     private static final int THUMBNAIL_SIZE = 250;
 
-    private static final double MAX_PERCENT_DIFFERENCE = 0.1;
+    private static final double MAX_PERCENT_DIFFERENCE = 0.3;
 
     public static void requireSimilar(@NonNull String relativePath, @NonNull BufferedImage image)
             throws IOException {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 5342494..6e6d6f67 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -47,6 +47,8 @@
 
     List<WifiConfiguration> getPrivilegedConfiguredNetworks();
 
+    WifiConfiguration getMatchingWifiConfig(in ScanResult scanResult);
+
     int addOrUpdateNetwork(in WifiConfiguration config);
 
     boolean removeNetwork(int netId);
@@ -113,6 +115,8 @@
 
     WifiConfiguration getWifiApConfiguration();
 
+    WifiConfiguration buildWifiConfig(String uriString, String mimeType, in byte[] data);
+
     void setWifiApConfiguration(in WifiConfiguration wifiConfig);
 
     void startWifi();
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 65ecf5d..dde8dba 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -26,84 +26,144 @@
     private static final boolean DBG = true;
     private static final String TAG = "RttManager";
 
-    /** @deprecated Type must be specified*/
+    /** @deprecated It is Not supported anymore. */
     @Deprecated
     public static final int RTT_TYPE_UNSPECIFIED        = 0;
-    public static final int RTT_TYPE_ONE_SIDED          = 1;
 
-    /** @deprecated It is not supported*/
+    public static final int RTT_TYPE_ONE_SIDED          = 1;
+    public static final int RTT_TYPE_TWO_SIDED          = 2;
+
+    /** @deprecated It is not supported anymore. */
     @Deprecated
     public static final int RTT_TYPE_11_V               = 2;
-    public static final int RTT_TYPE_TWO_SIDED          = 4;
 
-    /** @deprecated It is not supported*/
+    /** @deprecated It is not supported anymore. */
     @Deprecated
     public static final int RTT_TYPE_11_MC              = 4;
 
+    /** @deprecated It is not supported anymore. */
+    @Deprecated
     public static final int RTT_PEER_TYPE_UNSPECIFIED    = 0;
+
     public static final int RTT_PEER_TYPE_AP             = 1;
     public static final int RTT_PEER_TYPE_STA            = 2;       /* requires NAN */
+    public static final int RTT_PEER_P2P_GO              = 3;
+    public static final int RTT_PEER_P2P_CLIENT          = 4;
+    public static final int RTT_PEER_NAN                 = 5;
 
+    /**
+     * @deprecated It is not supported anymore.
+     * Use {@link android.net.wifi.RttManager#RTT_BW_20_SUPPORT} API.
+     */
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_20      = 0;
+
+    /**
+     * @deprecated It is not supported anymore.
+     * Use {@link android.net.wifi.RttManager#RTT_BW_40_SUPPORT} API.
+     */
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_40      = 1;
+
+    /**
+     * @deprecated It is not supported anymore.
+     * Use {@link android.net.wifi.RttManager#RTT_BW_80_SUPPORT} API.
+     */
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_80      = 2;
+
+    /**@deprecated It is not supported anymore.
+     * Use {@link android.net.wifi.RttManager#RTT_BW_160_SUPPORT} API.
+     */
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_160     = 3;
+
+    /**@deprecated not supported anymore*/
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_80P80   = 4;
+
+    /**@deprecated It is not supported anymore.
+     * Use {@link android.net.wifi.RttManager#RTT_BW_5_SUPPORT} API.
+     */
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_5       = 5;
+
+    /**@deprecated It is not supported anymore.
+     * Use {@link android.net.wifi.RttManager#RTT_BW_10_SUPPORT} API.
+     */
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_10      = 6;
 
-    /** @deprecated channel info must be specified*/
+    /** @deprecated channel info must be specified. */
     @Deprecated
     public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;
 
     public static final int RTT_STATUS_SUCCESS                  = 0;
+    /** General failure*/
     public static final int RTT_STATUS_FAILURE                  = 1;
+    /** Destination does not respond to RTT request*/
     public static final int RTT_STATUS_FAIL_NO_RSP              = 2;
+    /** RTT request is rejected by the destination. Double side RTT only*/
     public static final int RTT_STATUS_FAIL_REJECTED            = 3;
+    /** */
     public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET   = 4;
+    /** Timing measurement timeout*/
     public static final int RTT_STATUS_FAIL_TM_TIMEOUT          = 5;
+    /** Destination is on a different channel from the RTT Request*/
     public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL  = 6;
+    /** This type of Ranging is not support by Hardware*/
     public static final int RTT_STATUS_FAIL_NO_CAPABILITY       = 7;
+    /** Request abort fro uncertain reason*/
     public static final int RTT_STATUS_ABORTED                  = 8;
-    //if the T1-T4 or TOD/TOA Timestamp is illegal
+    /** The T1-T4 or TOD/TOA Timestamp is illegal*/
     public static final int RTT_STATUS_FAIL_INVALID_TS          = 9;
-    //11mc protocol failed, eg, unrecognized FTMR/FTM
+    /** 11mc protocol level failed, eg, unrecognized FTMR/FTM frame*/
     public static final int RTT_STATUS_FAIL_PROTOCOL            = 10;
+    /** Request can not be scheduled by hardware*/
     public static final int RTT_STATUS_FAIL_SCHEDULE            = 11;
+    /** destination is busy now, you can try after a specified time from destination*/
     public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER      = 12;
+    /** Bad Request argument*/
+    public static final int RTT_STATUS_INVALID_REQ              = 13;
+    /** Wifi is not enabled*/
+    public static final int RTT_STATUS_NO_WIFI                  = 14;
+    /** Responder overrides param info, cannot range with new params 2-side RTT only*/
+    public static final int RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE  = 15;
 
     public static final int REASON_UNSPECIFIED              = -1;
     public static final int REASON_NOT_AVAILABLE            = -2;
     public static final int REASON_INVALID_LISTENER         = -3;
     public static final int REASON_INVALID_REQUEST          = -4;
+    /** Do not have required permission */
+    public static final int REASON_PERMISSION_DENIED        = -5;
 
     public static final String DESCRIPTION_KEY  = "android.net.wifi.RttManager.Description";
 
     /**
-     * RTT BW supported bit mask
+     * RTT BW supported bit mask, used as RTT param bandWidth too
      */
-    public static final int RTT_BW_5_SUPPORT   = 0x1;
-    public static final int RTT_BW_10_SUPPORT  = 0x2;
-    public static final int RTT_BW_20_SUPPORT  = 0x4;
-    public static final int RTT_BW_40_SUPPORT  = 0x8;
+    public static final int RTT_BW_5_SUPPORT   = 0x01;
+    public static final int RTT_BW_10_SUPPORT  = 0x02;
+    public static final int RTT_BW_20_SUPPORT  = 0x04;
+    public static final int RTT_BW_40_SUPPORT  = 0x08;
     public static final int RTT_BW_80_SUPPORT  = 0x10;
     public static final int RTT_BW_160_SUPPORT = 0x20;
 
     /**
      * RTT Preamble Support bit mask
      */
-    public static final int PREAMBLE_LEGACY  = 0x1;
-    public static final int PREAMBLE_HT      = 0x2;
-    public static final int PREAMBLE_VHT     = 0x4;
+    public static final int PREAMBLE_LEGACY  = 0x01;
+    public static final int PREAMBLE_HT      = 0x02;
+    public static final int PREAMBLE_VHT     = 0x04;
 
-    /** @deprecated It has been replaced by RttCapabilities*/
+    /** @deprecated Use the new {@link android.net.wifi.RttManager.RttCapabilities} API */
     @Deprecated
     public class Capabilities {
         public int supportedType;
         public int supportedPeerType;
     }
 
-    /** @deprecated It has been replaced by getRttCapabilities*/
+    /** @deprecated Use the new {@link android.net.wifi.RttManager#getRttCapabilities()} API.*/
     @Deprecated
     public Capabilities getCapabilities() {
         return new Capabilities();
@@ -241,28 +301,35 @@
     /** specifies parameters for RTT request */
     public static class RttParams {
         /**
-         * type of destination device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA
+         * type of destination device being ranged
+         * currently only support RTT_PEER_TYPE_AP
+         * Range:RTT_PEER_TYPE_xxxx Default value:RTT_PEER_TYPE_AP
          */
         public int deviceType;
 
         /**
-         * type of RTT measurement method; one of RTT_TYPE_ONE_SIDED or RTT_TYPE_TWO_SIDED.
+         * type of RTT measurement method. Need check scan result and RttCapabilities first
+         * Range: RTT_TYPE_ONE_SIDED or RTT_TYPE_TWO_SIDED
+         * Default value: RTT_TYPE_ONE_SIDED
          */
         public int requestType;
 
-        /** mac address of the device being ranged */
+        /**
+         * mac address of the device being ranged
+         * Default value: null
+         */
         public String bssid;
 
         /**
-         * The primary 20 MHz frequency (in MHz) of the channel over which the client is
-         * communicating with the access point.Similar as ScanResult.frequency
+         * The primary control channel over which the client is
+         * communicating with the AP.Same as ScanResult.frequency
+         * Default value: 0
          */
         public int frequency;
 
         /**
-         * channel width used for RTT measurement. User need verify the highest BW the destination
-         * support (from scan result etc) before set this value. Wider channels result usually give
-         * better accuracy. However, the frame loss can increase. Similar as ScanResult.channelWidth
+         * channel width of the destination AP. Same as ScanResult.channelWidth
+         * Default value: 0
          */
         public int channelWidth;
 
@@ -270,77 +337,113 @@
          * Not used if the AP bandwidth is 20 MHz
          * If the AP use 40, 80 or 160 MHz, this is the center frequency
          * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
-         * similar as ScanResult.centerFreq0
+         * same as ScanResult.centerFreq0
+         * Default value: 0
          */
          public int centerFreq0;
 
          /**
           * Only used if the AP bandwidth is 80 + 80 MHz
           * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
-          * similar as ScanResult.centerFreq1
+          * same as ScanResult.centerFreq1
+          * Default value: 0
           */
           public int centerFreq1;
+
         /**
          * number of samples to be taken
-         * @deprecated  It has been replaced by numSamplesPerBurst
+         * @deprecated Use the new {@link android.net.wifi.RttManager.RttParams#numSamplesPerBurst}
          */
         @Deprecated
         public int num_samples;
 
         /**
          * number of retries if a sample fails
-         * @deprecated It has been replaced by numRetriesPerMeasurementFrame
+         * @deprecated
+         * Use {@link android.net.wifi.RttManager.RttParams#numRetriesPerMeasurementFrame} API.
          */
         @Deprecated
         public int num_retries;
 
-        /** Number of burst. fixed to 1 for single side RTT*/
+        /** Number of burst in exp , 2^x. 0 means single shot measurement, range 0-15
+         * Currently only single shot is supported
+         * Default value: 0
+         */
         public int numberBurst;
 
-        /** valid only if numberBurst > 1, interval between burst(ms). Not used by singe side RTT */
+        /**
+         * valid only if numberBurst > 1, interval between burst(100ms).
+         * Range : 0-31, 0--means no specific
+         * Default value: 0
+         */
         public int interval;
 
-        /** number of samples to be taken in one burst*/
+        /**
+         * number of samples to be taken in one burst
+         * Range: 1-31
+         * Default value: 8
+         */
         public int numSamplesPerBurst;
 
         /** number of retries for each measurement frame if a sample fails
-         *  Only used by single side RTT
+         *  Only used by single side RTT,
+         *  Range 0 - 3 Default value: 0
          */
         public int numRetriesPerMeasurementFrame;
 
-        /** number of retries for FTMR frame if fails Only used by 80211MC double side RTT */
+        /**
+         * number of retries for FTMR frame (control frame) if it fails.
+         * Only used by 80211MC double side RTT
+         * Range: 0-3  Default Value : 0
+         */
         public int numRetriesPerFTMR;
 
-        /** Request LCI information */
+        /**
+         * Request LCI information, only available when choose double side RTT measurement
+         * need check RttCapabilties first.
+         * Default value: false
+         * */
         public boolean LCIRequest;
 
-        /** Request LCR information */
+        /**
+         * Request LCR information, only available when choose double side RTT measurement
+         * need check RttCapabilties first.
+         * Default value: false
+         * */
         public boolean LCRRequest;
 
-        /** Timeout for each burst, unit of 250 us*/
+        /**
+         * Timeout for each burst, (250 * 2^x) us,
+         * Range 1-11 and 15. 15 means no control Default value: 15
+         * */
         public int burstTimeout;
 
         /** preamble used for RTT measurement
-         *  should be one of PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT
+         *  Range: PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT
+         *  Default value: PREAMBLE_HT
          */
         public int preamble;
 
         /** bandWidth used for RTT measurement.User need verify the highest BW the destination
          * support (from scan result etc) before set this value. Wider channels result usually give
          * better accuracy. However, the frame loss can increase too.
-         * should be one of RTT_CHANNEL_WIDTH_20 to RTT_CHANNEL_WIDTH_80
+         * should be one of RTT_BW_5_SUPPORT to RTT_BW_160_SUPPORT. However, need check
+         * RttCapabilities firstto verify HW support this bandwidth.
+         * Default value:RTT_BW_20_SUPPORT
          */
         public int bandwidth;
 
         public RttParams() {
             //provide initial value for RttParams
             deviceType = RTT_PEER_TYPE_AP;
-            numberBurst = 1;
+            requestType = RTT_TYPE_ONE_SIDED;
+            numberBurst = 0;
             numSamplesPerBurst = 8;
             numRetriesPerMeasurementFrame  = 0;
-            burstTimeout = 40 + numSamplesPerBurst *4;
-            preamble = PREAMBLE_LEGACY;
-            bandwidth = RTT_CHANNEL_WIDTH_20;
+            numRetriesPerFTMR = 0;
+            burstTimeout = 15;
+            preamble = PREAMBLE_HT;
+            bandwidth = RTT_BW_20_SUPPORT;
         }
     }
 
@@ -430,26 +533,29 @@
                 };
     }
 
-    public class wifiInformationElement {
-        /** Information Element ID*/
-        public int id;
-        public String data;
+    public static class WifiInformationElement {
+        /** Information Element ID 0xFF means element is invalid. */
+        public byte id;
+        public byte[] data;
     }
     /** specifies RTT results */
     public static class RttResult {
-        /** mac address of the device being ranged */
+        /** mac address of the device being ranged. */
         public String bssid;
 
-        /** # of burst for this measurement*/
+        /** # of burst for this measurement. */
         public int burstNumber;
 
-        /** total number of measurement frames in this measurement*/
+        /** total number of measurement frames attempted in this measurement. */
         public int measurementFrameNumber;
 
-        /** total successful number of measurement frames in this measurement*/
+        /** total successful number of measurement frames in this measurement. */
         public int successMeasurementFrameNumber;
 
-        /** Maximum number of frames per burst supported by peer */
+        /**
+         * Maximum number of frames per burst supported by peer. Two side RTT only
+         * Valid only if less than request
+         */
         public int frameNumberPerBurstPeer;
 
         /** status of the request */
@@ -457,120 +563,128 @@
 
         /**
          * type of the request used
-         * @deprecated It has been replaced by measurementType
+         * @deprecated Use {@link android.net.wifi.RttManager.RttResult#measurementType}
          */
         @Deprecated
         public int requestType;
 
-        /** RTT measurement method type used, shoudl be one of RTT_TYPE_ONE_SIDED or
+        /** RTT measurement method type used, should be one of RTT_TYPE_ONE_SIDED or
          *  RTT_TYPE_TWO_SIDED.
          */
         public int measurementType;
 
-        /** please retry RTT measurement after this S since peer indicate busy at ths moment*/
+        /**
+         * only valid when status ==  RTT_STATUS_FAIL_BUSY_TRY_LATER
+         * please retry RTT measurement after this duration since peer indicate busy at ths moment
+         *  Unit S  Range:1-31
+         */
         public int retryAfterDuration;
 
-        /** timestamp of completion, in microsecond since boot */
+        /** timestamp of completion, in microsecond since boot. */
         public long ts;
 
-        /** average RSSI observed, unit of 0.5 dB */
+        /** average RSSI observed, unit of 0.5 dB. */
         public int rssi;
 
         /**
          * RSSI spread (i.e. max - min)
-         * @deprecated It has been replaced by rssi_spread
+         * @deprecated Use {@link android.net.wifi.RttManager.RttResult#rssiSpread} API.
          */
         @Deprecated
         public int rssi_spread;
 
-        /**RSSI spread (i.e. max - min), unit of 0.5 dB */
+        /**RSSI spread (i.e. max - min), unit of 0.5 dB. */
         public int rssiSpread;
 
         /**
          * average transmit rate
-         * @deprecated It has been replaced by txRate
+         * @deprecated Use {@link android.net.wifi.RttManager.RttResult#txRate} API.
          */
         @Deprecated
         public int tx_rate;
 
-        /** average transmit rate */
+        /** average transmit rate. Unit (100kbps). */
         public int txRate;
 
-        /** average receiving rate */
+        /** average receiving rate Unit (100kbps). */
         public int rxRate;
 
        /**
         * average round trip time in nano second
-        * @deprecated  It has been replaced by rtt
+        * @deprecated  Use {@link android.net.wifi.RttManager.RttResult#rtt} API.
         */
         @Deprecated
         public long rtt_ns;
 
-        /** average round trip time in 0.1 nano second */
+        /** average round trip time in 0.1 nano second. */
         public long rtt;
 
         /**
          * standard deviation observed in round trip time
-         * @deprecated It has been replaced by rttStandardDeviation
+         * @deprecated Use {@link android.net.wifi.RttManager.RttResult#rttStandardDeviation} API.
          */
         @Deprecated
         public long rtt_sd_ns;
 
-        /** standard deviation of RTT in 0.1 ns */
+        /** standard deviation of RTT in 0.1 ns. */
         public long rttStandardDeviation;
 
         /**
          * spread (i.e. max - min) round trip time
-         * @deprecated It has been replaced by rttSpread
+         * @deprecated Use {@link android.net.wifi.RttManager.RttResult#rttSpread} API.
          */
         @Deprecated
         public long rtt_spread_ns;
 
-        /** spread (i.e. max - min) RTT in 0.1 ns */
+        /** spread (i.e. max - min) RTT in 0.1 ns. */
         public long rttSpread;
 
         /**
          * average distance in centimeter, computed based on rtt_ns
-         * @deprecated It has been replaced by distance
+         * @deprecated use {@link android.net.wifi.RttManager.RttResult#distance} API.
          */
         @Deprecated
         public int distance_cm;
 
-        /** average distance in cm, computed based on rtt */
+        /** average distance in cm, computed based on rtt. */
         public int distance;
 
         /**
          * standard deviation observed in distance
-         * @deprecated It has been replaced with distanceStandardDeviation
+         * @deprecated
+         * Use {@link .android.net.wifi.RttManager.RttResult#distanceStandardDeviation} API.
          */
         @Deprecated
         public int distance_sd_cm;
 
-        /** standard deviation observed in distance in cm*/
+        /** standard deviation observed in distance in cm. */
         public int distanceStandardDeviation;
 
         /**
          * spread (i.e. max - min) distance
-         * @deprecated It has been replaced by distanceSpread
+         * @deprecate Use {@link android.net.wifi.RttManager.RttResult#distanceSpread} API.
          */
         @Deprecated
         public int distance_spread_cm;
 
-        /** spread (i.e. max - min) distance in cm */
+        /** spread (i.e. max - min) distance in cm. */
         public int distanceSpread;
 
-        /** the duration of this measurement burst*/
+        /** the duration of this measurement burst, unit ms. */
         public int burstDuration;
 
-        /** LCI information Element*/
-        wifiInformationElement LCI;
+        /** Burst number supported by peer after negotiation, 2side RTT only*/
+        public int negotiatedBurstNum;
 
-        /** LCR information Element*/
-        wifiInformationElement LCR;
+        /** LCI information Element, only available for double side RTT. */
+        public WifiInformationElement LCI;
+
+        /** LCR information Element, only available to double side RTT. */
+        public WifiInformationElement LCR;
     }
 
 
-    /** pseudo-private class used to parcel results */
+    /** pseudo-private class used to parcel results. */
     public static class ParcelableRttResults implements Parcelable {
 
         public RttResult mResults[];
@@ -608,10 +722,17 @@
                     dest.writeInt(result.distanceStandardDeviation);
                     dest.writeInt(result.distanceSpread);
                     dest.writeInt(result.burstDuration);
-                    //dest.writeInt(result.LCI.id);
-                    //dest.writeString(result.LCI.data);
-                    //dest.writeInt(result.LCR.id);
-                    //dest.writeString(result.LCR.data);
+                    dest.writeInt(result.negotiatedBurstNum);
+                    dest.writeByte(result.LCI.id);
+                    if (result.LCI.id != (byte) 0xFF) {
+                        dest.writeByte((byte)result.LCI.data.length);
+                        dest.writeByteArray(result.LCI.data);
+                    }
+                    dest.writeByte(result.LCR.id);
+                    if (result.LCR.id != (byte) 0xFF) {
+                        dest.writeInt((byte) result.LCR.data.length);
+                        dest.writeByte(result.LCR.id);
+                    }
                 }
             } else {
                 dest.writeInt(0);
@@ -651,10 +772,21 @@
                             results[i].distanceStandardDeviation = in.readInt();
                             results[i].distanceSpread = in.readInt();
                             results[i].burstDuration = in.readInt();
-                            //results[i].LCI.id = in.readInt();
-                            //results[i].LCI.data = in.readString();
-                            //results[i].LCR.id = in.readInt();
-                            //results[i].LCR.data = in.readString();
+                            results[i].negotiatedBurstNum = in.readInt();
+                            results[i].LCI = new WifiInformationElement();
+                            results[i].LCI.id = in.readByte();
+                            if (results[i].LCI.id != (byte) 0xFF) {
+                                byte length = in.readByte();
+                                results[i].LCI.data = new byte[length];
+                                in.readByteArray(results[i].LCI.data);
+                            }
+                            results[i].LCR = new WifiInformationElement();
+                            results[i].LCR.id = in.readByte();
+                            if (results[i].LCR.id != (byte) 0xFF) {
+                                byte length = in.readByte();
+                                results[i].LCR.data = new byte[length];
+                                in.readByteArray(results[i].LCR.data);
+                            }
                         }
 
                         ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
@@ -678,7 +810,7 @@
         if (mRttCapabilities == null) {
             if(getRttCapabilities() == null) {
                 Log.e(TAG, "Can not get RTT capabilities");
-                //throw new IllegalStateException("RTT chip is not working");
+                throw new IllegalStateException("RTT chip is not working");
             }
         }
 
@@ -696,18 +828,24 @@
                 !mRttCapabilities.twoSided11McRttSupported) {
             Log.e(TAG, "Request " + index + ": two side RTT is not supported");
             return false;
-        } else if ( params.numberBurst <= 0 ) {
+        }  else if(params.bssid == null || params.bssid.isEmpty()) {
+            Log.e(TAG,"No BSSID is input");
+        } else if ( params.numberBurst != 0 ) {
             Log.e(TAG, "Request " + index + ": Illegal number of burst: " + params.numberBurst);
             return false;
-        } else if (params.numberBurst >  1 && params.interval <= 0) {
-            Log.e(TAG, "Request " + index + ": Illegal interval value: " + params.interval);
-            return false;
-        } else if (params.numSamplesPerBurst <= 0) {
+        } else if (params.numSamplesPerBurst <= 0 || params.numSamplesPerBurst > 31) {
             Log.e(TAG, "Request " + index + ": Illegal sample number per burst: " +
                     params.numSamplesPerBurst);
             return false;
-        } else if (params.numRetriesPerMeasurementFrame < 0 || params.numRetriesPerFTMR < 0) {
-            Log.e(TAG, "Request " + index + ": Illegal retry number");
+        } else if (params.numRetriesPerMeasurementFrame < 0 ||
+                params.numRetriesPerMeasurementFrame > 3) {
+            Log.e(TAG, "Request " + index + ": Illegal measurement frame retry number:" +
+                    params.numRetriesPerMeasurementFrame);
+            return false;
+        } else if(params.numRetriesPerFTMR < 0 ||
+                params.numRetriesPerFTMR > 3) {
+            Log.e(TAG, "Request " + index + ": Illegal FTMR frame retry number:" +
+                    params.numRetriesPerFTMR);
             return false;
         } else if (params.LCIRequest && !mRttCapabilities.lciSupported) {
             Log.e(TAG, "Request " + index + ": LCI is not supported");
@@ -715,7 +853,8 @@
         } else if (params.LCRRequest && !mRttCapabilities.lcrSupported) {
             Log.e(TAG, "Request " + index + ": LCR is not supported");
             return false;
-        } else if (params.burstTimeout <= 0){
+        } else if (params.burstTimeout < 1 ||
+                (params.burstTimeout > 11 && params.burstTimeout != 15)){
             Log.e(TAG, "Request " + index + ": Illegal burst timeout: " + params.burstTimeout);
             return false;
         } else if ((params.preamble & mRttCapabilities.preambleSupported) == 0) {
@@ -729,6 +868,15 @@
         return true;
     }
 
+    /**
+     * Request to start an RTT ranging
+     *
+     * @param params  -- RTT request Parameters
+     * @param listener -- Call back to inform RTT result
+     * @exception throw IllegalArgumentException when params are illegal
+     *            throw IllegalStateException when RttCapabilities do not exist
+     */
+
     public void startRanging(RttParams[] params, RttListener listener) {
         int index  = 0;
         for(RttParams rttParam : params) {
@@ -737,9 +885,9 @@
             }
             index++;
         }
-
         validateChannel();
         ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
+        Log.i(TAG, "Send RTT request to RTT Service");
         sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
                 0, putListener(listener), parcelableParams);
     }
@@ -887,6 +1035,7 @@
         }
         @Override
         public void handleMessage(Message msg) {
+            Log.i(TAG, "RTT manager get message: " + msg.what);
             switch (msg.what) {
                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
@@ -912,10 +1061,10 @@
 
             Object listener = getListener(msg.arg2);
             if (listener == null) {
-                if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
+                Log.e(TAG, "invalid listener key = " + msg.arg2 );
                 return;
             } else {
-                if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
+                Log.i(TAG, "listener key = " + msg.arg2);
             }
 
             switch (msg.what) {
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index e8a51e3..5dc70bd 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -261,6 +261,12 @@
         return freq > 4900 && freq < 5900;
     }
 
+    /**
+     *  @hide
+     * storing the raw bytes of full result IEs
+     **/
+    public byte[] bytes;
+
     /** information element from beacon
      * @hide
      */
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 34ae386..1521623 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.HashMap;
 import java.util.BitSet;
@@ -238,6 +239,7 @@
      * The band which AP resides on
      * 0-2G  1-5G
      * By default, 2G is chosen
+     * @hide
      */
     public int apBand = 0;
 
@@ -246,6 +248,7 @@
      * 2G  1-11
      * 5G  36,40,44,48,149,153,157,161,165
      * 0 - find a random available channel according to the apBand
+     * @hide
      */
     public int apChannel = 0;
 
@@ -401,13 +404,6 @@
      */
     public String autoJoinBSSID;
 
-    /**
-     * @hide
-     * BSSID list on which this configuration was seen.
-     * TODO: prevent this list to grow infinitely, age-out the results
-     */
-    public HashMap<String, ScanResult> scanResultCache;
-
     /** The Below RSSI thresholds are used to configure AutoJoin
      *  - GOOD/LOW/BAD thresholds are used so as to calculate link score
      *  - UNWANTED_SOFT are used by the blacklisting logic so as to handle
@@ -497,7 +493,7 @@
      * A summary of the RSSI and Band status for that configuration
      * This is used as a temporary value by the auto-join controller
      */
-    public final class Visibility {
+    public static final class Visibility {
         public int rssi5;   // strongest 5GHz RSSI
         public int rssi24;  // strongest 2.4GHz RSSI
         public int num5;    // number of BSSIDs on 5GHz
@@ -573,47 +569,8 @@
      * age in milliseconds: we will consider only ScanResults that are more recent,
      * i.e. younger.
      ***/
-    public Visibility setVisibility(long age) {
-        if (scanResultCache == null) {
-            visibility = null;
-            return null;
-        }
-
-        Visibility status = new Visibility();
-
-        long now_ms = System.currentTimeMillis();
-        for(ScanResult result : scanResultCache.values()) {
-            if (result.seen == 0)
-                continue;
-
-            if (result.is5GHz()) {
-                //strictly speaking: [4915, 5825]
-                //number of known BSSID on 5GHz band
-                status.num5 = status.num5 + 1;
-            } else if (result.is24GHz()) {
-                //strictly speaking: [2412, 2482]
-                //number of known BSSID on 2.4Ghz band
-                status.num24 = status.num24 + 1;
-            }
-
-            if ((now_ms - result.seen) > age) continue;
-
-            if (result.is5GHz()) {
-                if (result.level > status.rssi5) {
-                    status.rssi5 = result.level;
-                    status.age5 = result.seen;
-                    status.BSSID5 = result.BSSID;
-                }
-            } else if (result.is24GHz()) {
-                if (result.level > status.rssi24) {
-                    status.rssi24 = result.level;
-                    status.age24 = result.seen;
-                    status.BSSID24 = result.BSSID;
-                }
-            }
-        }
+    public void setVisibility(Visibility status) {
         visibility = status;
-        return status;
     }
 
     /** @hide */
@@ -909,41 +866,52 @@
      * @hide
      */
     public boolean isValid() {
+        String reason = strIsValid();
+        if (reason != null) {
+            Log.e("WFII", "WiFi Config not valid: " + reason);
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    private String strIsValid() {
 
         if (allowedKeyManagement == null)
-            return false;
+            return "allowed kmgmt";
 
         if (allowedKeyManagement.cardinality() > 1) {
             if (allowedKeyManagement.cardinality() != 2) {
-                return false;
+                return "cardinality != 2";
             }
-            if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) == false) {
-                return false;
+            if (!allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
+                return "not WPA_EAP";
             }
-            if ((allowedKeyManagement.get(KeyMgmt.IEEE8021X) == false)
-                    && (allowedKeyManagement.get(KeyMgmt.WPA_PSK) == false)) {
-                return false;
+            if ((!allowedKeyManagement.get(KeyMgmt.IEEE8021X))
+                    && (!allowedKeyManagement.get(KeyMgmt.WPA_PSK))) {
+                return "not PSK or 8021X";
             }
         }
 
-        if (TextUtils.isEmpty(FQDN) == false) {
+        if (!TextUtils.isEmpty(FQDN)) {
             /* this is passpoint configuration; it must not have an SSID */
-            if (TextUtils.isEmpty(SSID) == false) {
-                return false;
+            if (!TextUtils.isEmpty(SSID)) {
+                return "SSID not expected for Passpoint: '" + SSID + "'";
             }
             /* this is passpoint configuration; it must have a providerFriendlyName */
             if (TextUtils.isEmpty(providerFriendlyName)) {
-                return false;
+                return "no provider friendly name";
             }
             /* this is passpoint configuration; it must have enterprise config */
             if (enterpriseConfig == null
                     || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
-                return false;
+                return "no enterprise config";
             }
         }
 
         // TODO: Add more checks
-        return true;
+        return null;
     }
 
     /**
@@ -970,31 +938,6 @@
         return  false;
     }
 
-    /**
-     * most recent time we have seen this configuration
-     * @return most recent scanResult
-     * @hide
-     */
-    public ScanResult lastSeen() {
-        ScanResult mostRecent = null;
-
-        if (scanResultCache == null) {
-            return null;
-        }
-
-        for (ScanResult result : scanResultCache.values()) {
-            if (mostRecent == null) {
-                if (result.seen != 0)
-                   mostRecent = result;
-            } else {
-                if (result.seen > mostRecent.seen) {
-                   mostRecent = result;
-                }
-            }
-        }
-        return mostRecent;
-    }
-
     /** @hide **/
     public void setAutoJoinStatus(int status) {
         if (status < 0) status = 0;
@@ -1009,75 +952,6 @@
         }
     }
 
-    /** @hide
-     *  trim the scan Result Cache
-     * @param: number of entries to keep in the cache
-     */
-    public void trimScanResultsCache(int num) {
-        if (this.scanResultCache == null) {
-            return;
-        }
-        int currenSize = this.scanResultCache.size();
-        if (currenSize <= num) {
-            return; // Nothing to trim
-        }
-        ArrayList<ScanResult> list = new ArrayList<ScanResult>(this.scanResultCache.values());
-        if (list.size() != 0) {
-            // Sort by descending timestamp
-            Collections.sort(list, new Comparator() {
-                public int compare(Object o1, Object o2) {
-                    ScanResult a = (ScanResult)o1;
-                    ScanResult b = (ScanResult)o2;
-                    if (a.seen > b.seen) {
-                        return 1;
-                    }
-                    if (a.seen < b.seen) {
-                        return -1;
-                    }
-                    return a.BSSID.compareTo(b.BSSID);
-                }
-            });
-        }
-        for (int i = 0; i < currenSize - num ; i++) {
-            // Remove oldest results from scan cache
-            ScanResult result = list.get(i);
-            this.scanResultCache.remove(result.BSSID);
-        }
-    }
-
-    /* @hide */
-    private ArrayList<ScanResult> sortScanResults() {
-        ArrayList<ScanResult> list = new ArrayList<ScanResult>(this.scanResultCache.values());
-        if (list.size() != 0) {
-            Collections.sort(list, new Comparator() {
-                public int compare(Object o1, Object o2) {
-                    ScanResult a = (ScanResult)o1;
-                    ScanResult b = (ScanResult)o2;
-                    if (a.numIpConfigFailures > b.numIpConfigFailures) {
-                        return 1;
-                    }
-                    if (a.numIpConfigFailures < b.numIpConfigFailures) {
-                        return -1;
-                    }
-                    if (a.seen > b.seen) {
-                        return -1;
-                    }
-                    if (a.seen < b.seen) {
-                        return 1;
-                    }
-                    if (a.level > b.level) {
-                        return -1;
-                    }
-                    if (a.level < b.level) {
-                        return 1;
-                    }
-                    return a.BSSID.compareTo(b.BSSID);
-                }
-            });
-        }
-        return list;
-    }
-
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
@@ -1248,42 +1122,6 @@
                 }
             }
         }
-        if (this.scanResultCache != null) {
-            sbuf.append("Scan Cache:  ").append('\n');
-            ArrayList<ScanResult> list = sortScanResults();
-            if (list.size() > 0) {
-                for (ScanResult result : list) {
-                    long milli = now_ms - result.seen;
-                    long ageSec = 0;
-                    long ageMin = 0;
-                    long ageHour = 0;
-                    long ageMilli = 0;
-                    long ageDay = 0;
-                    if (now_ms > result.seen && result.seen > 0) {
-                        ageMilli = milli % 1000;
-                        ageSec   = (milli / 1000) % 60;
-                        ageMin   = (milli / (60*1000)) % 60;
-                        ageHour  = (milli / (60*60*1000)) % 24;
-                        ageDay   = (milli / (24*60*60*1000));
-                    }
-                    sbuf.append("{").append(result.BSSID).append(",").append(result.frequency);
-                    sbuf.append(",").append(String.format("%3d", result.level));
-                    if (result.autoJoinStatus > 0) {
-                        sbuf.append(",st=").append(result.autoJoinStatus);
-                    }
-                    if (ageSec > 0 || ageMilli > 0) {
-                        sbuf.append(String.format(",%4d.%02d.%02d.%02d.%03dms", ageDay,
-                                ageHour, ageMin, ageSec, ageMilli));
-                    }
-                    if (result.numIpConfigFailures > 0) {
-                        sbuf.append(",ipfail=");
-                        sbuf.append(result.numIpConfigFailures);
-                    }
-                    sbuf.append("} ");
-                }
-                sbuf.append('\n');
-            }
-        }
         sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
         sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
         sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1577,11 +1415,6 @@
 
             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
 
-            if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) {
-                scanResultCache = new HashMap<String, ScanResult>();
-                scanResultCache.putAll(source.scanResultCache);
-            }
-
             if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
                 connectChoices = new HashMap<String, Integer>();
                 connectChoices.putAll(source.connectChoices);
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 440ad61..3525ec2 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -56,6 +56,8 @@
     /** @hide */
     public static final String ALTSUBJECT_MATCH_KEY = "altsubject_match";
     /** @hide */
+    public static final String DOM_SUFFIX_MATCH_KEY = "domain_suffix_match";
+    /** @hide */
     public static final String OPP_KEY_CACHING     = "proactive_key_caching";
     /**
      * String representing the keystore OpenSSL ENGINE's ID.
@@ -577,6 +579,36 @@
     }
 
     /**
+     * Set the domain_suffix_match directive on wpa_supplicant. This is the parameter to use
+     * for Hotspot 2.0 defined matching of AAA server certs per WFA HS2.0 spec, section 7.3.3.2,
+     * second paragraph.
+     *
+     * From wpa_supplicant documentation:
+     * Constraint for server domain name. If set, this FQDN is used as a suffix match requirement
+     * for the AAAserver certificate in SubjectAltName dNSName element(s). If a matching dNSName is
+     * found, this constraint is met. If no dNSName values are present, this constraint is matched
+     * against SubjectName CN using same suffix match comparison.
+     * Suffix match here means that the host/domain name is compared one label at a time starting
+     * from the top-level domain and all the labels in domain_suffix_match shall be included in the
+     * certificate. The certificate may include additional sub-level labels in addition to the
+     * required labels.
+     * For example, domain_suffix_match=example.com would match test.example.com but would not
+     * match test-example.com.
+     * @param domain The domain value
+     */
+    public void setDomainSuffixMatch(String domain) {
+        setFieldValue(DOM_SUFFIX_MATCH_KEY, domain);
+    }
+
+    /**
+     * Get the domain_suffix_match value. See setDomSuffixMatch.
+     * @return The domain value.
+     */
+    public String getDomainSubjectMatch() {
+        return getFieldValue(DOM_SUFFIX_MATCH_KEY, "");
+    }
+
+    /**
      * Set realm for passpoint credential
      * @param realm the realm
      */
@@ -601,7 +633,7 @@
     }
 
     /**
-     * Set plmn for passpoint credential
+     * Get plmn for passpoint credential
      * @return the plmn
      */
     public String getPlmn() {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f8a6e3f..2058645 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -623,6 +623,20 @@
     }
 
     /**
+     * Returns a WifiConfiguration matching this ScanResult
+     * @param scanResult scanResult that represents the BSSID
+     * @return {@link WifiConfiguration} that matches this BSSID or null
+     * @hide
+     */
+    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
+        try {
+            return mService.getMatchingWifiConfig(scanResult);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Add a new network description to the set of configured networks.
      * The {@code networkId} field of the supplied configuration object
      * is ignored.
@@ -1466,6 +1480,20 @@
     }
 
     /**
+     * Builds a WifiConfiguration from Hotspot 2.0 MIME file.
+     * @return AP details in WifiConfiguration
+     *
+     * @hide Dont open yet
+     */
+    public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) {
+        try {
+            return mService.buildWifiConfig(uriString, mimeType, data);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Sets the Wi-Fi AP Configuration.
      * @return {@code true} if the operation succeeded, {@code false} otherwise
      *