Merge "Support different SIM power states"
diff --git a/api/current.txt b/api/current.txt
index 0353a8b..55dda04 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37531,6 +37531,7 @@
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+    field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
diff --git a/api/system-current.txt b/api/system-current.txt
index eb6b7b1..5e9c7e3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -40702,6 +40702,7 @@
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+    field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
diff --git a/api/test-current.txt b/api/test-current.txt
index 8946daf..5487a97 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -37630,6 +37630,7 @@
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+    field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6320134..234bef7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -44,7 +44,6 @@
 import android.telephony.SubscriptionManager;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.SparseArray;
 import android.util.SparseIntArray;
 
 import com.android.internal.telephony.ITelephony;
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index 0d62054..b72e783 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -53,7 +53,7 @@
 
     private final boolean mIsOwner;
     private final long mMemoryAddr;
-    private int mFd;
+    private int mFd = -1;
 
     /**
      * Creates a new instance.
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 6000fb5..d73e7dd 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <grp.h>
 #include <inttypes.h>
+#include <malloc.h>
 #include <mntent.h>
 #include <paths.h>
 #include <signal.h>
@@ -519,6 +520,9 @@
     // The child process.
     gMallocLeakZygoteChild = 1;
 
+    // Set the jemalloc decay time to 1.
+    mallopt(M_DECAY_TIME, 1);
+
     // Clean up any descriptors which must be closed immediately
     DetachDescriptors(env, fdsToClose);
 
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 10166a5..0cafed6 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -48,9 +48,6 @@
          provisioning, availability etc -->
     <bool name="config_carrier_vt_available">true</bool>
 
-    <!-- Flag specifying whether VoLTE availability is based on provisioning -->
-    <bool name="config_carrier_volte_provisioned">true</bool>
-
     <bool name="config_auto_attach_data_on_creation">false</bool>
 
     <!--Thresholds for LTE dbm in status bar-->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 22a1a36..37d03ad 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2328,9 +2328,6 @@
          provisioning, availability etc -->
     <bool name="config_carrier_volte_available">false</bool>
 
-    <!-- Flag specifying whether VoLTE availability is based on provisioning -->
-    <bool name="config_carrier_volte_provisioned">false</bool>
-
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">true</bool>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ea89cc1..f3ce719 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2262,7 +2262,6 @@
   <java-symbol type="bool" name="imsServiceAllowTurnOff" />
   <java-symbol type="bool" name="config_device_volte_available" />
   <java-symbol type="bool" name="config_carrier_volte_available" />
-  <java-symbol type="bool" name="config_carrier_volte_provisioned" />
   <java-symbol type="bool" name="config_carrier_volte_tty_supported" />
   <java-symbol type="bool" name="config_device_vt_available" />
   <java-symbol type="bool" name="config_device_respects_hold_carrier_config" />
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index faf04b1..e69a2cc 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -17,7 +17,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
     frameworks-base-testutils \
-    mockito-target
+    mockito-target \
+    legacy-android-tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
@@ -27,4 +28,4 @@
 
 include $(BUILD_PACKAGE)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index e46f166..ae0c8a0 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -45,6 +45,7 @@
     <permission name="android.permission.BLUETOOTH_STACK" >
         <group gid="bluetooth" />
         <group gid="wakelock" />
+        <group gid="uhid" />
     </permission>
 
     <permission name="android.permission.NET_TUNNELING" >
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0835cad..8efda2a 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -20,9 +20,11 @@
 # =============================
 # This contains the junit.framework and android.test classes that were in
 # Android API level 25 excluding those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
 LOCAL_MODULE := legacy-test
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
@@ -30,20 +32,35 @@
 include $(BUILD_JAVA_LIBRARY)
 
 # Build the legacy-android-test library
-# =============================
+# =====================================
 # This contains the android.test classes that were in Android API level 25,
 # including those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src/android) \
-    $(call all-java-files-under, ../test-runner/src/android)
+    $(call all-java-files-under, ../test-runner/src/android) \
+    $(call all-java-files-under, src/com)
 LOCAL_MODULE := legacy-android-test
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
+# Build the legacy-android-tests library
+# ======================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, tests)
+LOCAL_MODULE := legacy-android-tests
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
 ifeq ($(HOST_OS),linux)
 # Build the legacy-performance-test-hostdex library
 # =================================================
diff --git a/core/java/com/android/internal/util/Predicate.java b/legacy-test/src/com/android/internal/util/Predicate.java
similarity index 100%
rename from core/java/com/android/internal/util/Predicate.java
rename to legacy-test/src/com/android/internal/util/Predicate.java
diff --git a/core/java/com/android/internal/util/Predicates.java b/legacy-test/src/com/android/internal/util/Predicates.java
similarity index 99%
rename from core/java/com/android/internal/util/Predicates.java
rename to legacy-test/src/com/android/internal/util/Predicates.java
index c006564..fe1ff15 100644
--- a/core/java/com/android/internal/util/Predicates.java
+++ b/legacy-test/src/com/android/internal/util/Predicates.java
@@ -21,6 +21,8 @@
 /**
  * Predicates contains static methods for creating the standard set of
  * {@code Predicate} objects.
+ *
+ * @hide
  */
 public class Predicates {
 
diff --git a/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java b/legacy-test/tests/com/android/internal/util/PredicatesTest.java
similarity index 100%
rename from core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
rename to legacy-test/tests/com/android/internal/util/PredicatesTest.java
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 6394c64..34465e9 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -122,6 +122,11 @@
         WebSettings webSettings = myWebView.getSettings();
         webSettings.setJavaScriptEnabled(true);
         webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+        webSettings.setUseWideViewPort(true);
+        webSettings.setLoadWithOverviewMode(true);
+        webSettings.setSupportZoom(true);
+        webSettings.setBuiltInZoomControls(true);
+        webSettings.setDisplayZoomControls(false);
         mWebViewClient = new MyWebViewClient();
         myWebView.setWebViewClient(mWebViewClient);
         myWebView.setWebChromeClient(new MyWebChromeClient());
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4f7b834..bee1659e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -487,7 +487,7 @@
             new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS);
 
     private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) {
-        synchronized(mValidationLogs) {
+        synchronized (mValidationLogs) {
             while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
                 mValidationLogs.removeLast();
             }
@@ -1671,7 +1671,7 @@
     }
 
     private void sendStickyBroadcast(Intent intent) {
-        synchronized(this) {
+        synchronized (this) {
             if (!mSystemReady) {
                 mInitialBroadcast = new Intent(intent);
             }
@@ -1712,7 +1712,7 @@
     void systemReady() {
         loadGlobalProxy();
 
-        synchronized(this) {
+        synchronized (this) {
             mSystemReady = true;
             if (mInitialBroadcast != null) {
                 mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL);
@@ -3494,7 +3494,7 @@
         enforceCrossUserPermission(userId);
         throwIfLockdownEnabled();
 
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn != null) {
                 return vpn.prepare(oldPackage, newPackage);
@@ -3521,7 +3521,7 @@
     public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) {
         enforceCrossUserPermission(userId);
 
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn != null) {
                 vpn.setPackageAuthorization(packageName, authorized);
@@ -3540,7 +3540,7 @@
     public ParcelFileDescriptor establishVpn(VpnConfig config) {
         throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             return mVpns.get(user).establish(config);
         }
     }
@@ -3557,7 +3557,7 @@
             throw new IllegalStateException("Missing active network connection");
         }
         int user = UserHandle.getUserId(Binder.getCallingUid());
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
         }
     }
@@ -3571,7 +3571,7 @@
     public LegacyVpnInfo getLegacyVpnInfo(int userId) {
         enforceCrossUserPermission(userId);
 
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             return mVpns.get(userId).getLegacyVpnInfo();
         }
     }
@@ -3587,7 +3587,7 @@
             return new VpnInfo[0];
         }
 
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             List<VpnInfo> infoList = new ArrayList<>();
             for (int i = 0; i < mVpns.size(); i++) {
                 VpnInfo info = createVpnInfo(mVpns.valueAt(i));
@@ -3635,7 +3635,7 @@
     @Override
     public VpnConfig getVpnConfig(int userId) {
         enforceCrossUserPermission(userId);
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn != null) {
                 return vpn.getVpnConfig();
@@ -3669,7 +3669,7 @@
                 return true;
             }
             int user = UserHandle.getUserId(Binder.getCallingUid());
-            synchronized(mVpns) {
+            synchronized (mVpns) {
                 Vpn vpn = mVpns.get(user);
                 if (vpn == null) {
                     Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
@@ -3904,7 +3904,7 @@
     }
 
     private void onUserStart(int userId) {
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             Vpn userVpn = mVpns.get(userId);
             if (userVpn != null) {
                 loge("Starting user already has a VPN");
@@ -3919,7 +3919,7 @@
     }
 
     private void onUserStop(int userId) {
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             Vpn userVpn = mVpns.get(userId);
             if (userVpn == null) {
                 loge("Stopped user has no VPN");
@@ -3931,7 +3931,7 @@
     }
 
     private void onUserAdded(int userId) {
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             final int vpnsSize = mVpns.size();
             for (int i = 0; i < vpnsSize; i++) {
                 Vpn vpn = mVpns.valueAt(i);
@@ -3941,7 +3941,7 @@
     }
 
     private void onUserRemoved(int userId) {
-        synchronized(mVpns) {
+        synchronized (mVpns) {
             final int vpnsSize = mVpns.size();
             for (int i = 0; i < vpnsSize; i++) {
                 Vpn vpn = mVpns.valueAt(i);
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index b64c65d..9f7437e 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -26,6 +26,8 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -73,6 +75,7 @@
     private long mNitzTimeSetTime = NOT_SET;
     // TODO: Have a way to look up the timezone we are in
     private long mNitzZoneSetTime = NOT_SET;
+    private Network mDefaultNetwork = null;
 
     private Context mContext;
     private TrustedTime mTime;
@@ -82,6 +85,8 @@
     private AlarmManager mAlarmManager;
     private PendingIntent mPendingPollIntent;
     private SettingsObserver mSettingsObserver;
+    private ConnectivityManager mCM;
+    private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
     // The last time that we successfully fetched the NTP time.
     private long mLastNtpFetchTime = NOT_SET;
     private final PowerManager.WakeLock mWakeLock;
@@ -103,6 +108,7 @@
         mContext = context;
         mTime = NtpTrustedTime.getInstance(context);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         Intent pollIntent = new Intent(ACTION_POLL, null);
         mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
 
@@ -123,13 +129,12 @@
     public void systemRunning() {
         registerForTelephonyIntents();
         registerForAlarms();
-        registerForConnectivityIntents();
 
         HandlerThread thread = new HandlerThread(TAG);
         thread.start();
         mHandler = new MyHandler(thread.getLooper());
-        // Check the network time on the new thread
-        mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+        mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+        mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
 
         mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
         mSettingsObserver.observe(mContext);
@@ -152,15 +157,10 @@
             }, new IntentFilter(ACTION_POLL));
     }
 
-    private void registerForConnectivityIntents() {
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        mContext.registerReceiver(mConnectivityReceiver, intentFilter);
-    }
-
     private void onPollNetworkTime(int event) {
-        // If Automatic time is not set, don't bother.
-        if (!isAutomaticTimeRequested()) return;
+        // If Automatic time is not set, don't bother. Similarly, if we don't
+        // have any default network, don't bother.
+        if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
         mWakeLock.acquire();
         try {
             onPollNetworkTimeUnderWakeLock(event);
@@ -262,22 +262,6 @@
         }
     };
 
-    /** Receiver for ConnectivityManager events */
-    private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
-                if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION ");
-                // Don't bother checking if we have connectivity, NtpTrustedTime does that for us.
-                Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED);
-                // Send with a short delay to make sure the network is ready for use
-                mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS);
-            }
-        }
-    };
-
     /** Handler to do the network accesses on */
     private class MyHandler extends Handler {
 
@@ -297,6 +281,21 @@
         }
     }
 
+    private class NetworkTimeUpdateCallback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            Log.d(TAG, String.format("New default network %s; checking time.", network));
+            mDefaultNetwork = network;
+            // Running on mHandler so invoke directly.
+            onPollNetworkTime(EVENT_NETWORK_CHANGED);
+        }
+
+        @Override
+        public void onLost(Network network) {
+            if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+        }
+    }
+
     /** Observer to watch for changes to the AUTO_TIME setting */
     private static class SettingsObserver extends ContentObserver {
 
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index d38beb3..44c61f0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.content.Context.TELEPHONY_SERVICE;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -47,9 +48,9 @@
 public class TetheringConfiguration {
     private static final String TAG = TetheringConfiguration.class.getSimpleName();
 
-    private static final int DUN_NOT_REQUIRED = 0;
-    private static final int DUN_REQUIRED = 1;
-    private static final int DUN_UNSPECIFIED = 2;
+    public static final int DUN_NOT_REQUIRED = 0;
+    public static final int DUN_REQUIRED = 1;
+    public static final int DUN_UNSPECIFIED = 2;
 
     // USB is  192.168.42.1 and 255.255.255.0
     // Wifi is 192.168.43.1 and 255.255.255.0
@@ -81,8 +82,9 @@
         tetherableBluetoothRegexs = ctx.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_bluetooth_regexs);
 
-        isDunRequired = checkDunRequired(ctx);
-        preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, isDunRequired);
+        final int dunCheck = checkDunRequired(ctx);
+        preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
+        isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
 
         dhcpRanges = getDhcpRanges(ctx);
         defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
@@ -138,14 +140,12 @@
         pw.println();
     }
 
-    private static boolean checkDunRequired(Context ctx) {
-        final TelephonyManager tm = ctx.getSystemService(TelephonyManager.class);
-        final int secureSetting =
-                (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
-        return (secureSetting == DUN_REQUIRED);
+    private static int checkDunRequired(Context ctx) {
+        final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
+        return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
     }
 
-    private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, boolean requiresDun) {
+    private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
         final int ifaceTypes[] = ctx.getResources().getIntArray(
                 com.android.internal.R.array.config_tether_upstream_types);
         final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
@@ -153,10 +153,10 @@
             switch (i) {
                 case TYPE_MOBILE:
                 case TYPE_MOBILE_HIPRI:
-                    if (requiresDun) continue;
+                    if (dunCheck == DUN_REQUIRED) continue;
                     break;
                 case TYPE_MOBILE_DUN:
-                    if (!requiresDun) continue;
+                    if (dunCheck == DUN_NOT_REQUIRED) continue;
                     break;
             }
             upstreamIfaceTypes.add(i);
@@ -166,7 +166,7 @@
         // of the value of |requiresDun|, cell data of one form or another is
         // *always* an upstream, regardless of the upstream interface types
         // specified by configuration resources.
-        if (requiresDun) {
+        if (dunCheck == DUN_REQUIRED) {
             if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
                 upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
             }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b9d22e8..24cd3c7 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -682,7 +682,7 @@
             }
 
             // send broadcast intent only if the USB state has changed
-            if (!isUsbStateChanged(intent)) {
+            if (!isUsbStateChanged(intent) && !configChanged) {
                 if (DEBUG) {
                     Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
                 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e1239d0..7d22a2c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -57,6 +57,13 @@
     // system image, that can be added in packages/apps/CarrierConfig.
 
     /**
+     * This flag specifies whether VoLTE availability is based on provisioning. By default this is
+     * false.
+     */
+    public static final String
+            KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
+
+    /**
      * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
      * events from the Sim.
      * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
@@ -1376,6 +1383,8 @@
         sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
         sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
+
+        sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
         sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
         sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index fc406ee..58262e1 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -22,7 +22,6 @@
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.DeadObjectException;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.telephony.mbms.IMbmsStreamingManagerCallback;
@@ -96,15 +95,15 @@
     /**
      * Create a new MbmsStreamingManager using the given subscription ID.
      *
-     * Note that this call will bind a remote service and that may take a bit.  This
-     * may throw an {@link MbmsException}, indicating errors that may happen during
-     * the initialization or binding process.
+     * Note that this call will bind a remote service. You may not call this method on your app's
+     * main thread. This may throw an {@link MbmsException}, indicating errors that may happen
+     * during the initialization or binding process.
      *
-     * @param context
-     * @param listener
-     * @param streamingAppName
-     * @param subscriptionId
-     * @return
+     * @param context The {@link Context} to use.
+     * @param listener A callback object on which you wish to receive results of asynchronous
+     *                 operations.
+     * @param streamingAppName The name of the streaming app, as specified by the carrier.
+     * @param subscriptionId The subscription ID to use.
      */
     public static MbmsStreamingManager create(Context context,
             IMbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
@@ -117,9 +116,7 @@
 
     /**
      * Create a new MbmsStreamingManager using the system default data subscription ID.
-     *
-     * Note that this call will bind a remote service and that may take a bit.  This
-     * may throw an IllegalArgumentException or RemoteException.
+     * See {@link #create(Context, IMbmsStreamingManagerCallback, String, int)}.
      */
     public static MbmsStreamingManager create(Context context,
             IMbmsStreamingManagerCallback listener, String streamingAppName)
@@ -156,19 +153,29 @@
      *
      * Multiple calls replace the list of serviceClasses of interest.
      *
-     * May throw an IllegalArgumentException or RemoteException.
+     * This may throw an {@link MbmsException} containing one of the following errors:
+     * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
+     * {@link MbmsException#ERROR_NOT_YET_INITIALIZED}
+     * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
      *
-     * Synchronous responses include
-     * <li>SUCCESS</li>
-     * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
-     *
-     * Asynchronous errors through the listener include any of the errors except
-     * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
-     * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
-     * <li>ERROR_MSDC_END_OF_SESSION</li>
+     * Asynchronous error codes via the {@link IMbmsStreamingManagerCallback#error(int, String)}
+     * callback can include any of the errors except:
+     * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
+     * {@link MbmsException#ERROR_INVALID_SERVICE_ID}
+     * {@link MbmsException#ERROR_END_OF_SESSION}
      */
-    public int getStreamingServices(List<String> classList) {
-        return 0;
+    public void getStreamingServices(List<String> classList) throws MbmsException {
+        if (mService == null) {
+            throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+        }
+        try {
+            int returnCode = mService.getStreamingServices(mAppName, mSubscriptionId, classList);
+            if (returnCode != MbmsException.SUCCESS) {
+                throw new MbmsException(returnCode);
+            }
+        } catch (RemoteException e) {
+            throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
+        }
     }
 
     /**
@@ -262,7 +269,7 @@
             } catch (RemoteException e) {
                 mService = null;
                 Log.e(LOG_TAG, "Service died before initialization");
-                throw new MbmsException(MbmsException.ERROR_INITIALIZATION_REMOTE_EXCEPTION);
+                throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
             }
         }
     }
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
new file mode 100644
index 0000000..0cb4cff
--- /dev/null
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.telephony.ITelephony;
+
+/**
+ * Allows applications to request the system to perform a network scan.
+ *
+ * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} will
+ * receive a NetworkScan which contains the callback method to stop the scan requested.
+ * @hide
+ */
+public class NetworkScan {
+
+    public static final String TAG = "NetworkScan";
+
+    public static final int SUCCESS = 0;
+    public static final int ERROR_INVALID_SCAN = 1;
+    public static final int ERROR_UNSUPPORTED = 2;
+    public static final int ERROR_INTERRUPTED = 3;
+    public static final int ERROR_CANCELLED = 4;
+
+    private final int mScanId;
+    private final int mSubId;
+
+    /**
+     * Stops the network scan
+     *
+     * This is the callback method to stop an ongoing scan. When user requests a new scan,
+     * a NetworkScan object will be returned, and the user can stop the scan by calling this
+     * method.
+     */
+    public void stop() throws RemoteException {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.stopNetworkScan(mSubId, mScanId);
+            } else {
+                throw new RemoteException("Failed to get the ITelephony instance.");
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "stopNetworkScan  RemoteException", ex);
+            throw new RemoteException("Failed to stop the network scan with id " + mScanId);
+        }
+    }
+
+    /**
+     * Creates a new NetworkScan with scanId
+     *
+     * @param scanId The id of the scan
+     * @param subId the id of the subscription
+     * @hide
+     */
+    public NetworkScan(int scanId, int subId) {
+        mScanId = scanId;
+        mSubId = subId;
+    }
+
+    private ITelephony getITelephony() {
+        return ITelephony.Stub.asInterface(
+            ServiceManager.getService(Context.TELEPHONY_SERVICE));
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkScanRequest.aidl b/telephony/java/android/telephony/NetworkScanRequest.aidl
new file mode 100644
index 0000000..5addb1c
--- /dev/null
+++ b/telephony/java/android/telephony/NetworkScanRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable NetworkScanRequest;
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
new file mode 100644
index 0000000..0a542a7
--- /dev/null
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Defines a request to peform a network scan.
+ *
+ * This class defines whether the network scan will be performed only once or periodically until
+ * cancelled, when the scan is performed periodically, the time interval is not controlled by the
+ * user but defined by the modem vendor.
+ * @hide
+ */
+public final class NetworkScanRequest implements Parcelable {
+
+    /** Performs the scan only once */
+    public static final int SCAN_TYPE_ONE_SHOT = 0;
+    /**
+     * Performs the scan periodically until cancelled
+     *
+     * The modem will start new scans periodically, and the interval between two scans is usually
+     * multiple minutes.
+     * */
+    public static final int SCAN_TYPE_PERIODIC = 1;
+
+    /** Defines the type of the scan. */
+    public int scanType;
+
+    /** Describes the radio access technologies with bands or channels that need to be scanned. */
+    public RadioAccessSpecifier[] specifiers;
+
+    /**
+     * Creates a new NetworkScanRequest with scanType and network specifiers
+     *
+     * @param scanType The type of the scan
+     * @param specifiers the radio network with bands / channels to be scanned
+     */
+    public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers) {
+        this.scanType = scanType;
+        this.specifiers = specifiers;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(scanType);
+        dest.writeParcelableArray(specifiers, flags);
+    }
+
+    private NetworkScanRequest(Parcel in) {
+        scanType = in.readInt();
+        specifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
+                Object.class.getClassLoader(),
+                RadioAccessSpecifier.class);
+    }
+
+    @Override
+    public boolean equals (Object o) {
+        NetworkScanRequest nsr;
+
+        try {
+            nsr = (NetworkScanRequest) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return (scanType == nsr.scanType
+                && Arrays.equals(specifiers, nsr.specifiers));
+    }
+
+    @Override
+    public int hashCode () {
+        return ((scanType * 31)
+                + (Arrays.hashCode(specifiers)) * 37);
+    }
+
+    public static final Creator<NetworkScanRequest> CREATOR =
+            new Creator<NetworkScanRequest>() {
+                @Override
+                public NetworkScanRequest createFromParcel(Parcel in) {
+                    return new NetworkScanRequest(in);
+                }
+
+                @Override
+                public NetworkScanRequest[] newArray(int size) {
+                    return new NetworkScanRequest[size];
+                }
+            };
+}
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.aidl b/telephony/java/android/telephony/RadioAccessSpecifier.aidl
new file mode 100644
index 0000000..7e09e0b
--- /dev/null
+++ b/telephony/java/android/telephony/RadioAccessSpecifier.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable RadioAccessSpecifier;
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java
new file mode 100644
index 0000000..33ce8b4
--- /dev/null
+++ b/telephony/java/android/telephony/RadioAccessSpecifier.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Describes a particular radio access network to be scanned.
+ *
+ * The scan can be performed on either bands or channels for a specific radio access network type.
+ * @hide
+ */
+public final class RadioAccessSpecifier implements Parcelable {
+
+    /**
+     * The radio access network that needs to be scanned
+     *
+     * See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
+     */
+    public int radioAccessNetwork;
+
+    /**
+     * The frequency bands that need to be scanned
+     *
+     * bands must be used together with radioAccessNetwork
+     *
+     * See {@link RadioNetworkConstants} for details.
+     */
+    public int[] bands;
+
+    /**
+     * The frequency channels that need to be scanned
+     *
+     * channels must be used together with radioAccessNetwork
+     *
+     * See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
+     */
+    public int[] channels;
+
+    /**
+    * Creates a new RadioAccessSpecifier with radio network, bands and channels
+    *
+    * The user must specify the radio network type, and at least specify either of frequency
+    * bands or channels.
+    *
+    * @param ran The type of the radio access network
+    * @param bands the frequency bands to be scanned
+    * @param channels the frequency bands to be scanned
+    */
+    public RadioAccessSpecifier(int ran, int[] bands, int[] channels) {
+        this.radioAccessNetwork = ran;
+        this.bands = bands;
+        this.channels = channels;
+    }
+
+    public static final Parcelable.Creator<RadioAccessSpecifier> CREATOR =
+            new Parcelable.Creator<RadioAccessSpecifier> (){
+                @Override
+                public RadioAccessSpecifier createFromParcel(Parcel in) {
+                    return new RadioAccessSpecifier(in);
+                }
+
+                @Override
+                public RadioAccessSpecifier[] newArray(int size) {
+                    return new RadioAccessSpecifier[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(radioAccessNetwork);
+        dest.writeIntArray(bands);
+        dest.writeIntArray(channels);
+    }
+
+    private RadioAccessSpecifier(Parcel in) {
+        radioAccessNetwork = in.readInt();
+        bands = in.createIntArray();
+        channels = in.createIntArray();
+    }
+
+    @Override
+    public boolean equals (Object o) {
+        RadioAccessSpecifier ras;
+
+        try {
+            ras = (RadioAccessSpecifier) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return (radioAccessNetwork == ras.radioAccessNetwork
+                && Arrays.equals(bands, ras.bands)
+                && Arrays.equals(channels, ras.channels));
+    }
+
+    @Override
+    public int hashCode () {
+        return ((radioAccessNetwork * 31)
+                + (Arrays.hashCode(bands) * 37)
+                + (Arrays.hashCode(channels)) * 39);
+    }
+}
diff --git a/telephony/java/android/telephony/RadioNetworkConstants.java b/telephony/java/android/telephony/RadioNetworkConstants.java
new file mode 100644
index 0000000..1a9072d
--- /dev/null
+++ b/telephony/java/android/telephony/RadioNetworkConstants.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+/**
+ * Contains radio access network related constants.
+ * @hide
+ */
+public final class RadioNetworkConstants {
+
+    public static final class RadioAccessNetworks {
+        public static final int GERAN = 1;
+        public static final int UTRAN = 2;
+        public static final int EUTRAN = 3;
+        /** @hide */
+        public static final int CDMA2000 = 4;
+    }
+
+    /**
+     * Frenquency bands for GERAN.
+     * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
+     */
+    public static final class GeranBands {
+        public static final int BAND_T380 = 1;
+        public static final int BAND_T410 = 2;
+        public static final int BAND_450 = 3;
+        public static final int BAND_480 = 4;
+        public static final int BAND_710 = 5;
+        public static final int BAND_750 = 6;
+        public static final int BAND_T810 = 7;
+        public static final int BAND_850 = 8;
+        public static final int BAND_P900 = 9;
+        public static final int BAND_E900 = 10;
+        public static final int BAND_R900 = 11;
+        public static final int BAND_DCS1800 = 12;
+        public static final int BAND_PCS1900 = 13;
+        public static final int BAND_ER900 = 14;
+    }
+
+    /**
+     * Frenquency bands for UTRAN.
+     * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
+     */
+    public static final class UtranBands {
+        public static final int BAND_1 = 1;
+        public static final int BAND_2 = 2;
+        public static final int BAND_3 = 3;
+        public static final int BAND_4 = 4;
+        public static final int BAND_5 = 5;
+        public static final int BAND_6 = 6;
+        public static final int BAND_7 = 7;
+        public static final int BAND_8 = 8;
+        public static final int BAND_9 = 9;
+        public static final int BAND_10 = 10;
+        public static final int BAND_11 = 11;
+        public static final int BAND_12 = 12;
+        public static final int BAND_13 = 13;
+        public static final int BAND_14 = 14;
+        /** band 15, 16, 17, 18 are reserved */
+        public static final int BAND_19 = 19;
+        public static final int BAND_20 = 20;
+        public static final int BAND_21 = 21;
+        public static final int BAND_22 = 22;
+        /** band 23, 24 are reserved */
+        public static final int BAND_25 = 25;
+        public static final int BAND_26 = 26;
+    }
+
+    /**
+     * Frenquency bands for EUTRAN.
+     * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
+     */
+    public static final class EutranBands {
+        public static final int BAND_1 = 1;
+        public static final int BAND_2 = 2;
+        public static final int BAND_3 = 3;
+        public static final int BAND_4 = 4;
+        public static final int BAND_5 = 5;
+        public static final int BAND_6 = 6;
+        public static final int BAND_7 = 7;
+        public static final int BAND_8 = 8;
+        public static final int BAND_9 = 9;
+        public static final int BAND_10 = 10;
+        public static final int BAND_11 = 11;
+        public static final int BAND_12 = 12;
+        public static final int BAND_13 = 13;
+        public static final int BAND_14 = 14;
+        public static final int BAND_17 = 17;
+        public static final int BAND_18 = 18;
+        public static final int BAND_19 = 19;
+        public static final int BAND_20 = 20;
+        public static final int BAND_21 = 21;
+        public static final int BAND_22 = 22;
+        public static final int BAND_23 = 23;
+        public static final int BAND_24 = 24;
+        public static final int BAND_25 = 25;
+        public static final int BAND_26 = 26;
+        public static final int BAND_27 = 27;
+        public static final int BAND_28 = 28;
+        public static final int BAND_30 = 30;
+        public static final int BAND_31 = 31;
+        public static final int BAND_33 = 33;
+        public static final int BAND_34 = 34;
+        public static final int BAND_35 = 35;
+        public static final int BAND_36 = 36;
+        public static final int BAND_37 = 37;
+        public static final int BAND_38 = 38;
+        public static final int BAND_39 = 39;
+        public static final int BAND_40 = 40;
+        public static final int BAND_41 = 41;
+        public static final int BAND_42 = 42;
+        public static final int BAND_43 = 43;
+        public static final int BAND_44 = 44;
+        public static final int BAND_45 = 45;
+        public static final int BAND_46 = 46;
+        public static final int BAND_47 = 47;
+        public static final int BAND_48 = 48;
+        public static final int BAND_65 = 65;
+        public static final int BAND_66 = 66;
+        public static final int BAND_68 = 68;
+        public static final int BAND_70 = 70;
+    }
+
+    /**
+     * Frenquency bands for CDMA2000.
+     * http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
+     * @hide
+     *
+     * TODO(yinxu): Check with the nexus team about the definition of CDMA bands.
+     */
+    public static final class CdmaBands {
+        public static final int BAND_0 = 1;
+        public static final int BAND_1 = 2;
+        public static final int BAND_2 = 3;
+        public static final int BAND_3 = 4;
+        public static final int BAND_4 = 5;
+        public static final int BAND_5 = 6;
+        public static final int BAND_6 = 7;
+        public static final int BAND_7 = 8;
+        public static final int BAND_8 = 9;
+        public static final int BAND_9 = 10;
+        public static final int BAND_10 = 11;
+        public static final int BAND_11 = 12;
+        public static final int BAND_12 = 13;
+        public static final int BAND_13 = 14;
+        public static final int BAND_14 = 15;
+        public static final int BAND_15 = 16;
+        public static final int BAND_16 = 17;
+        public static final int BAND_17 = 18;
+        public static final int BAND_18 = 19;
+        public static final int BAND_19 = 20;
+        public static final int BAND_20 = 21;
+        public static final int BAND_21 = 22;
+    }
+}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index d6e74cf..dcdda86 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -463,9 +463,28 @@
      */
     public static SubmitPdu getSubmitPdu(String scAddress,
             String destinationAddress, String message, boolean statusReportRequested) {
-        SubmitPduBase spb;
+        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
+                SubscriptionManager.getDefaultSmsSubscriptionId());
+    }
 
-        if (useCdmaFormatForMoSms()) {
+    /**
+     * Get an SMS-SUBMIT PDU for a destination address and a message.
+     * This method will not attempt to use any GSM national language 7 bit encodings.
+     *
+     * @param scAddress Service Centre address.  Null means use default.
+     * @param destinationAddress the address of the destination for the message.
+     * @param message String representation of the message payload.
+     * @param statusReportRequested Indicates whether a report is requested for this message.
+     * @param subId Subscription of the message
+     * @return a <code>SubmitPdu</code> containing the encoded SC
+     *         address, if applicable, and the encoded message.
+     *         Returns null on encode error.
+     * @hide
+     */
+    public static SubmitPdu getSubmitPdu(String scAddress,
+            String destinationAddress, String message, boolean statusReportRequested, int subId) {
+        SubmitPduBase spb;
+        if (useCdmaFormatForMoSms(subId)) {
             spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
                     destinationAddress, message, statusReportRequested, null);
         } else {
@@ -758,12 +777,27 @@
      * @return true if Cdma format should be used for MO SMS, false otherwise.
      */
     private static boolean useCdmaFormatForMoSms() {
-        if (!SmsManager.getDefault().isImsSmsSupported()) {
+        // IMS is registered with SMS support, check the SMS format supported
+        return useCdmaFormatForMoSms(SubscriptionManager.getDefaultSmsSubscriptionId());
+    }
+
+    /**
+     * Determines whether or not to use CDMA format for MO SMS.
+     * If SMS over IMS is supported, then format is based on IMS SMS format,
+     * otherwise format is based on current phone type.
+     *
+     * @param subId Subscription for which phone type is returned.
+     *
+     * @return true if Cdma format should be used for MO SMS, false otherwise.
+     */
+    private static boolean useCdmaFormatForMoSms(int subId) {
+        SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
+        if (!smsManager.isImsSmsSupported()) {
             // use Voice technology to determine SMS format.
-            return isCdmaVoice();
+            return isCdmaVoice(subId);
         }
         // IMS is registered with SMS support, check the SMS format supported
-        return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
+        return (SmsConstants.FORMAT_3GPP2.equals(smsManager.getImsSmsFormat()));
     }
 
     /**
@@ -772,10 +806,18 @@
      * @return true if current phone type is cdma, false otherwise.
      */
     private static boolean isCdmaVoice() {
-        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
-        return (PHONE_TYPE_CDMA == activePhone);
+        return isCdmaVoice(SubscriptionManager.getDefaultSmsSubscriptionId());
     }
 
+     /**
+      * Determines whether or not to current phone type is cdma
+      *
+      * @return true if current phone type is cdma, false otherwise.
+      */
+     private static boolean isCdmaVoice(int subId) {
+         int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(subId);
+         return (PHONE_TYPE_CDMA == activePhone);
+   }
     /**
      * Decide if the carrier supports long SMS.
      * {@hide}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 047c0cf..3fcb280 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -39,6 +39,11 @@
 import android.provider.Settings.SettingNotFoundException;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -144,6 +149,7 @@
     private final Context mContext;
     private final int mSubId;
     private SubscriptionManager mSubscriptionManager;
+    private TelephonyScanManager mTelephonyScanManager;
 
     private static String multiSimConfig =
             SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
@@ -4573,6 +4579,32 @@
     }
 
     /**
+     * Request a network scan.
+     *
+     * This method is asynchronous, so the network scan results will be returned by callback.
+     * The returned NetworkScan will contain a callback method which can be used to stop the scan.
+     *
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param request Contains all the RAT with bands/channels that need to be scanned.
+     * @param callback Returns network scan results or errors.
+     * @return A NetworkScan obj which contains a callback which can stop the scan.
+     * @hide
+     */
+    public NetworkScan requestNetworkScan(
+            NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
+        synchronized (this) {
+            if (mTelephonyScanManager == null) {
+                mTelephonyScanManager = new TelephonyScanManager();
+            }
+        }
+        return mTelephonyScanManager.requestNetworkScan(getSubId(), request, callback);
+    }
+
+    /**
      * Ask the radio to connect to the input network and change selection mode to manual.
      *
      * <p>
@@ -6482,5 +6514,26 @@
         }
         return false;
     }
+
+    /**
+     * Get the most recently available signal strength information.
+     *
+     * Get the most recent SignalStrength information reported by the modem. Due
+     * to power saving this information may not always be current.
+     * @return the most recent cached signal strength info from the modem
+     * @hide
+     */
+    @Nullable
+    public SignalStrength getSignalStrength() {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getSignalStrength(getSubId());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getSignalStrength", e);
+        }
+        return null;
+    }
 }
 
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
new file mode 100644
index 0000000..c905d3a
--- /dev/null
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.SparseArray;
+import java.util.List;
+
+import com.android.internal.telephony.ITelephony;
+
+/**
+ * Manages the radio access network scan requests and callbacks.
+ * @hide
+ */
+public final class TelephonyScanManager {
+
+    private static final String TAG = "TelephonyScanManager";
+
+    /** @hide */
+    public static final int CALLBACK_SCAN_RESULTS = 1;
+    /** @hide */
+    public static final int CALLBACK_SCAN_ERROR = 2;
+    /** @hide */
+    public static final int CALLBACK_SCAN_COMPLETE = 3;
+
+    /**
+     * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should
+     * implement and provide this callback so that the scan results or errors can be returned.
+     */
+    public static abstract class NetworkScanCallback {
+        /** Returns the scan results to the user, this callback will be called multiple times. */
+        public void onResults(List<CellInfo> results) {}
+
+        /**
+         * Informs the user that the scan has stopped.
+         *
+         * This callback will be called when the scan is finished or cancelled by the user.
+         * The related NetworkScanRequest will be deleted after this callback.
+         */
+        public void onComplete() {}
+
+        /**
+         * Informs the user that there is some error about the scan.
+         *
+         * This callback will be called whenever there is any error about the scan, but the scan
+         * won't stop unless the onComplete() callback is called.
+         */
+        public void onError(int error) {}
+    }
+
+    private static class NetworkScanInfo {
+        private final NetworkScanRequest mRequest;
+        private final NetworkScanCallback mCallback;
+
+        NetworkScanInfo(NetworkScanRequest request, NetworkScanCallback callback) {
+            mRequest = request;
+            mCallback = callback;
+        }
+    }
+
+    private final Looper mLooper;
+    private final Messenger mMessenger;
+    private SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>();
+
+    public TelephonyScanManager() {
+        HandlerThread thread = new HandlerThread(TAG);
+        thread.start();
+        mLooper = thread.getLooper();
+        mMessenger = new Messenger(new Handler(mLooper) {
+            @Override
+            public void handleMessage(Message message) {
+                checkNotNull(message, "message cannot be null");
+                NetworkScanInfo nsi;
+                synchronized (mScanInfo) {
+                    nsi = mScanInfo.get(message.arg2);
+                }
+                if (nsi == null) {
+                    throw new RuntimeException(
+                        "Failed to find NetworkScanInfo with id " + message.arg2);
+                }
+                NetworkScanCallback callback = nsi.mCallback;
+                if (callback == null) {
+                    throw new RuntimeException(
+                        "Failed to find NetworkScanCallback with id " + message.arg2);
+                }
+
+                switch (message.what) {
+                    case CALLBACK_SCAN_RESULTS:
+                        try {
+                            callback.onResults((List<CellInfo>) message.obj);
+                        } catch (Exception e) {
+                            Rlog.e(TAG, "Exception in networkscan callback onResults", e);
+                        }
+                        break;
+                    case CALLBACK_SCAN_ERROR:
+                        try {
+                            callback.onError(message.arg1);
+                        } catch (Exception e) {
+                            Rlog.e(TAG, "Exception in networkscan callback onError", e);
+                        }
+                        break;
+                    case CALLBACK_SCAN_COMPLETE:
+                        try {
+                            callback.onComplete();
+                            mScanInfo.remove(message.arg2);
+                        } catch (Exception e) {
+                            Rlog.e(TAG, "Exception in networkscan callback onComplete", e);
+                        }
+                        break;
+                    default:
+                        Rlog.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
+                        break;
+                }
+            }
+        });
+    }
+
+    /**
+     * Request a network scan.
+     *
+     * This method is asynchronous, so the network scan results will be returned by callback.
+     * The returned NetworkScan will contain a callback method which can be used to stop the scan.
+     *
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param request Contains all the RAT with bands/channels that need to be scanned.
+     * @param callback Returns network scan results or errors.
+     * @return A NetworkScan obj which contains a callback which can stop the scan.
+     * @hide
+     */
+    public NetworkScan requestNetworkScan(int subId,
+            NetworkScanRequest request, NetworkScanCallback callback) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                int scanId = telephony.requestNetworkScan(subId, request, mMessenger, new Binder());
+                saveScanInfo(scanId, request, callback);
+                return new NetworkScan(scanId, subId);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "requestNetworkScan RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "requestNetworkScan NPE", ex);
+        }
+        return null;
+    }
+
+    private void saveScanInfo(int id, NetworkScanRequest request, NetworkScanCallback callback) {
+        synchronized (mScanInfo) {
+            mScanInfo.put(id, new NetworkScanInfo(request, callback));
+        }
+    }
+
+    private ITelephony getITelephony() {
+        return ITelephony.Stub.asInterface(
+            ServiceManager.getService(Context.TELEPHONY_SERVICE));
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
index 7b4ecf2..6d2e031 100755
--- a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
@@ -17,7 +17,6 @@
 package android.telephony.mbms;
 
 import android.net.Uri;
-import android.telephony.SignalStrength;
 import android.telephony.mbms.StreamingService;
 
 /**
@@ -27,5 +26,5 @@
     void error(int errorCode, String message);
     void streamStateChanged(in StreamingService service, int state);
     void uriUpdated(in Uri uri);
-    void signalStrengthUpdated(in SignalStrength signalStrength);
+    void broadcastSignalStrengthUpdated(int signalStrength);
 }
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index cc4a02a..e8680ea 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -16,16 +16,21 @@
 
 package android.telephony.mbms;
 
-import android.os.RemoteException;
-
 /** @hide */
-public class MbmsException extends RemoteException {
+public class MbmsException extends Exception {
     public static final int SUCCESS = 0;
     public static final int ERROR_NO_SERVICE_INSTALLED = 1;
     public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2;
     public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3;
-    public static final int ERROR_INITIALIZATION_REMOTE_EXCEPTION = 4;
+    public static final int ERROR_UNKNOWN_REMOTE_EXCEPTION = 4;
     public static final int ERROR_ALREADY_INITIALIZED = 5;
+    public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6;
+    public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7;
+    public static final int ERROR_UNABLE_TO_START_SERVICE = 8;
+    public static final int ERROR_INVALID_SERVICE_ID = 9;
+    public static final int ERROR_END_OF_SESSION = 10;
+    public static final int ERROR_NOT_YET_INITIALIZED = 11;
+    public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 12;
 
     private final int mErrorCode;
 
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index cb621c8..f167f0ab 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -114,6 +114,7 @@
         sessionEndTime = (java.util.Date) in.readSerializable();
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         Set<Locale> keySet = names.keySet();
         dest.writeInt(keySet.size());
@@ -128,7 +129,33 @@
         dest.writeSerializable(sessionEndTime);
     }
 
+    @Override
     public int describeContents() {
         return 0;
     }
+
+    public Map<Locale, String> getNames() {
+        return names;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public String getServiceId() {
+        return serviceId;
+    }
+
+    public Date getSessionStartTime() {
+        return sessionStartTime;
+    }
+
+    public Date getSessionEndTime() {
+        return sessionEndTime;
+    }
+
 }
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 8cc6043..08c4a27 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -19,7 +19,6 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.SignalStrength;
 
 /**
  * @hide
@@ -69,17 +68,6 @@
     public void stopStreaming() {
     }
 
-    /**
-     * Switch this stream to a different service.  Used for smooth transitions.
-     *
-     * This may throw a RemoteException.
-     *
-     * Asynchronous errors through the listener include any of the errors except
-     * <li>ERROR_MSDC_UNABLE_TO_INITIALIZE</li>
-     */
-    public void switchStream(StreamingServiceInfo streamingServiceInfo) {
-    }
-
     public void dispose() {
     }
 
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
index 7f5c486..752a4b3 100644
--- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -17,7 +17,6 @@
 package android.telephony.mbms;
 
 import android.net.Uri;
-import android.telephony.SignalStrength;
 
 /**
  * A Callback class for use when the applicaiton is actively streaming content.
@@ -25,6 +24,15 @@
  */
 public class StreamingServiceCallback extends IStreamingServiceCallback.Stub {
 
+    /**
+     * Indicates broadcast signal strength is not available for this service.
+     *
+     * This may be due to the service no longer being available due to geography
+     * or timing (end of service) or because lack of demand has caused the service
+     * to be delivered via unicast.
+     */
+    public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1;
+
 
     public void error(int errorCode, String message) {
         // default implementation empty
@@ -51,19 +59,16 @@
     }
 
     /**
-     * Signal Strength updated.
+     * Broadcast Signal Strength updated.
      *
      * This signal strength is the BROADCAST signal strength which,
      * depending on technology in play and it's deployment, may be
      * stronger or weaker than the traditional UNICAST signal
-     * strength.
-     *
-     * A {@link android.telephony.SignalStrength#getLevel} result of 0 means
-     * you don't have coverage for this stream, either due to geographic
-     * restrictions, poor tower coverage or something (yards of concrete?)
-     * interferring with the signal.
+     * strength.  It a simple int from 0-4 for valid levels or
+     * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
+     * for this service due to timing, geography or popularity.
      */
-    public void signalStrengthUpdated(SignalStrength signalStrength) {
+    public void broadcastSignalStrengthUpdated(int signalStrength) {
         // default implementation empty
     }
 }
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index ddc661d..a77a10a 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -21,7 +21,6 @@
 import android.telephony.mbms.IStreamingServiceCallback;
 import android.telephony.mbms.StreamingService;
 import android.telephony.mbms.StreamingServiceInfo;
-import android.telephony.SignalStrength;
 
 /**
  * The interface the opaque MbmsStreamingService will satisfy.
@@ -29,22 +28,8 @@
  */
 interface IMbmsStreamingService
 {
-    /**
-     * Initialize streaming service
-     * Registers this listener, subId with this appName
-     *
-     */
     int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId);
 
-
-    /**
-     * - Registers serviceClasses of interest with the uid/appName/subId key.
-     * - Starts asynch fetching data on streaming services of matching classes to be reported
-     * later by callback.
-     *
-     * Note that subsequent calls with the same callback, appName, subId and uid will replace
-     * the service class list.
-     */
     int getStreamingServices(String appName, int subId, in List<String> serviceClasses);
 
     /**
@@ -69,8 +54,6 @@
 
     Uri getPlaybackUri(String appName, int subId, String serviceId);
 
-    void switchStreams(String appName, int subId, String oldServiceId, String newServiceId);
-
     int getState(String appName, int subId, String serviceId);
 
     void stopStreaming(String appName, int subId, String serviceId);
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index 9f0c0e9..4670352 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -20,7 +20,7 @@
 import android.os.RemoteException;
 import android.telephony.mbms.IMbmsStreamingManagerCallback;
 import android.telephony.mbms.IStreamingServiceCallback;
-import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.MbmsException;
 
 import java.util.List;
 
@@ -29,16 +29,42 @@
  * TODO: future systemapi
  */
 public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
-
+    /**
+     * Initialize streaming service for this app and subId, registering the listener.
+     *
+     * @param listener The callback to use to communicate with the app.
+     * @param appName The app name as negotiated with the wireless carrier.
+     * @param subscriptionId The subscription ID to use.
+     * @return {@link MbmsException#SUCCESS}, {@link MbmsException#ERROR_ALREADY_INITIALIZED}, or
+     *         {@link MbmsException#ERROR_APP_PERMISSIONS_NOT_GRANTED}
+     */
     @Override
-    public int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId)
-            throws RemoteException {
+    public int initialize(IMbmsStreamingManagerCallback listener, String appName,
+            int subscriptionId) throws RemoteException {
         return 0;
     }
 
+    /**
+     * Registers serviceClasses of interest with the appName/subId key.
+     * Starts async fetching data on streaming services of matching classes to be reported
+     * later via {@link IMbmsStreamingManagerCallback#streamingServicesUpdated(List)}
+     *
+     * Note that subsequent calls with the same uid, appName and subId will replace
+     * the service class list.
+     *
+     * @param appName The app name as negotiated with the wireless carrier.
+     * @param subscriptionId The subscription id to use.
+     * @param serviceClasses The service classes that the app wishes to get info on. The strings
+     *                       may contain arbitrary data as negotiated between the app and the
+     *                       carrier.
+     * @return One of {@link MbmsException#SUCCESS},
+     *         {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND},
+     *         {@link MbmsException#ERROR_NOT_YET_INITIALIZED}, or
+     *         {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+     */
     @Override
-    public int getStreamingServices(String appName, int subId, List<String> serviceClasses)
-            throws RemoteException {
+    public int getStreamingServices(String appName, int subscriptionId,
+            List<String> serviceClasses) throws RemoteException {
         return 0;
     }
 
@@ -59,11 +85,6 @@
     }
 
     @Override
-    public void switchStreams(String appName, int subId, String oldServiceId, String newServiceId)
-            throws RemoteException {
-    }
-
-    @Override
     public int getState(String appName, int subId, String serviceId) throws RemoteException {
         return 0;
     }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dbf99f1..c542879 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -19,6 +19,8 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Messenger;
 import android.os.ResultReceiver;
 import android.net.Uri;
 import android.service.carrier.CarrierIdentifier;
@@ -29,8 +31,10 @@
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.NetworkScanRequest;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.telephony.TelephonyHistogram;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import com.android.ims.internal.IImsServiceController;
@@ -794,6 +798,26 @@
     CellNetworkScanResult getCellNetworkScanResults(int subId);
 
     /**
+     * Perform a radio network scan and return the id of this scan.
+     *
+     * @param subId the id of the subscription.
+     * @param request Defines all the configs for network scan.
+     * @param messenger Callback messages will be sent using this messenger.
+     * @param binder the binder object instantiated in TelephonyManager.
+     * @return An id for this scan.
+     */
+    int requestNetworkScan(int subId, in NetworkScanRequest request, in Messenger messenger,
+            in IBinder binder);
+
+    /**
+     * Stop an existing radio network scan.
+     *
+     * @param subId the id of the subscription.
+     * @param scanId The id of the scan that is going to be stopped.
+     */
+    void stopNetworkScan(int subId, int scanId);
+
+    /**
      * Ask the radio to connect to the input network and change selection mode to manual.
      *
      * @param subId the id of the subscription.
@@ -1293,4 +1317,15 @@
      * @hide
      */
     boolean getEmergencyCallbackMode(int subId);
+
+    /**
+     * Get the most recently available signal strength information.
+     *
+     * Get the most recent SignalStrength information reported by the modem. Due
+     * to power saving this information may not always be current.
+     * @param subId Subscription index
+     * @return the most recent cached signal strength info from the modem
+     * @hide
+     */
+    SignalStrength getSignalStrength(int subId);
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 954b17f..e50901f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -466,5 +466,6 @@
     int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
     int RIL_UNSOL_LCEDATA_RECV = 1045;
     int RIL_UNSOL_PCO_DATA = 1046;
-    int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1047;
+    int RIL_UNSOL_MODEM_RESTART = 1047;
+    int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1048;
 }
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index 50eaafb..7313a28 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -20,8 +20,7 @@
 import android.content.Context;
 import android.os.PerformanceCollector.PerformanceResultsWriter;
 
-import com.google.android.collect.Lists;
-
+import java.util.ArrayList;
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestListener;
@@ -48,7 +47,7 @@
     private Context mContext;
     private boolean mSkipExecution = false;
 
-    private List<TestListener> mTestListeners = Lists.newArrayList();
+    private List<TestListener> mTestListeners = new ArrayList<>();
     private Instrumentation mInstrumentation;
     private PerformanceResultsWriter mPerfWriter;
 
@@ -58,7 +57,8 @@
 
         if (shouldRunSingleTestMethod(testMethodName, testClass)) {
             TestCase testCase = buildSingleTestMethod(testClass, testMethodName);
-            mTestCases = Lists.newArrayList(testCase);
+            mTestCases = new ArrayList<>();
+            mTestCases.add(testCase);
             mTestClassName = testClass.getSimpleName();
         } else {
             setTest(getTest(testClass), testClass);
diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
index 1ab7c7f..2cf76af 100644
--- a/test-runner/src/android/test/ClassPathPackageInfo.java
+++ b/test-runner/src/android/test/ClassPathPackageInfo.java
@@ -16,9 +16,8 @@
 
 package android.test;
 
-import com.google.android.collect.Sets;
-
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -44,7 +43,7 @@
     }
 
     public Set<ClassPathPackageInfo> getSubpackages() {
-        Set<ClassPathPackageInfo> info = Sets.newHashSet();
+        Set<ClassPathPackageInfo> info = new HashSet<>();
         for (String name : subpackageNames) {
             info.add(source.getPackageInfo(name));
         }
@@ -52,7 +51,7 @@
     }
 
     public Set<Class<?>> getTopLevelClassesRecursive() {
-        Set<Class<?>> set = Sets.newHashSet();
+        Set<Class<?>> set = new HashSet<>();
         addTopLevelClassesTo(set);
         return set;
     }
diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
index 89bb494..9bcc25a 100644
--- a/test-runner/src/android/test/ClassPathPackageInfoSource.java
+++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java
@@ -17,13 +17,13 @@
 package android.test;
 
 import android.util.Log;
-import com.google.android.collect.Maps;
-import com.google.android.collect.Sets;
 import dalvik.system.DexFile;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -57,7 +57,7 @@
     private static String[] apkPaths;
 
     // A cache of jar file contents
-    private final Map<File, Set<String>> jarFiles = Maps.newHashMap();
+    private final Map<File, Set<String>> jarFiles = new HashMap<>();
     private ClassLoader classLoader;
 
     ClassPathPackageInfoSource() {
@@ -76,7 +76,7 @@
     private ClassPathPackageInfo createPackageInfo(String packageName) {
         Set<String> subpackageNames = new TreeSet<String>();
         Set<String> classNames = new TreeSet<String>();
-        Set<Class<?>> topLevelClasses = Sets.newHashSet();
+        Set<Class<?>> topLevelClasses = new HashSet<>();
         findClasses(packageName, classNames, subpackageNames);
         for (String className : classNames) {
             if (className.endsWith(".R") || className.endsWith(".Manifest")) {
@@ -248,7 +248,7 @@
             throws IOException {
         Set<String> entryNames = jarFiles.get(jarFile);
         if (entryNames == null) {
-            entryNames = Sets.newHashSet();
+            entryNames = new HashSet<>();
             ZipFile zipFile = new ZipFile(jarFile);
             Enumeration<? extends ZipEntry> entries = zipFile.entries();
             while (entries.hasMoreElements()) {
diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
index 42ef48b..1980d92 100644
--- a/test-runner/src/android/test/DatabaseTestUtils.java
+++ b/test-runner/src/android/test/DatabaseTestUtils.java
@@ -16,11 +16,10 @@
 
 package android.test;
 
-import com.google.android.collect.Sets;
-
 import android.database.sqlite.SQLiteDatabase;
 import android.database.Cursor;
 
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -42,7 +41,7 @@
     }
 
     private static Set<String> getSchemaSet(SQLiteDatabase db) {
-        Set<String> schemaSet = Sets.newHashSet();
+        Set<String> schemaSet = new HashSet<>();
 
         Cursor entityCursor = db.rawQuery("SELECT sql FROM sqlite_master", null);
         try {
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index 3abf38f..0b77c00 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -16,8 +16,6 @@
 
 package android.test;
 
-import com.google.android.collect.Lists;
-
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
@@ -38,6 +36,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
 import java.util.List;
 
@@ -55,7 +54,7 @@
     private ContentResolver mResolver;
     private final MockAccountManager mMockAccountManager;
 
-    private List<Intent> mBroadcastIntents = Lists.newArrayList();
+    private List<Intent> mBroadcastIntents = new ArrayList<>();
 
     public IsolatedContext(
             ContentResolver resolver, Context targetContext) {
@@ -67,7 +66,7 @@
     /** Returns the list of intents that were broadcast since the last call to this method. */
     public List<Intent> getAndClearBroadcastIntents() {
         List<Intent> intents = mBroadcastIntents;
-        mBroadcastIntents = Lists.newArrayList();
+        mBroadcastIntents = new ArrayList<>();
         return intents;
     }
 
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 36786b0..fd33321 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -16,20 +16,24 @@
 
 package android.test;
 
-import com.google.android.collect.Sets;
-
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.ContentProvider;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
-import android.os.FileUtils;
 import android.util.Log;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -48,8 +52,8 @@
     private File mCacheDir;
     private final Object mSync = new Object();
 
-    private Set<String> mDatabaseNames = Sets.newHashSet();
-    private Set<String> mFileNames = Sets.newHashSet();
+    private Set<String> mDatabaseNames = new HashSet<>();
+    private Set<String> mFileNames = new HashSet<>();
 
     public static <T extends ContentProvider> T providerWithRenamedContext(
             Class<T> contentProvider, Context c, String filePrefix)
@@ -237,10 +241,14 @@
                     Log.w("RenamingDelegatingContext", "Unable to create cache directory");
                     return null;
                 }
-                FileUtils.setPermissions(
-                        mCacheDir.getPath(),
-                        FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-                        -1, -1);
+                try {
+                    // Give the directory all possible permissions.
+                    Files.setPosixFilePermissions(mCacheDir.toPath(),
+                            EnumSet.allOf(PosixFilePermission.class));
+                } catch (IOException e) {
+                    Log.e("RenamingDelegatingContext",
+                            "Could not set permissions of test cacheDir", e);
+                }
             }
         }
         return mCacheDir;
diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java
index c46d403..dc053a2 100644
--- a/test-runner/src/android/test/TestCaseUtil.java
+++ b/test-runner/src/android/test/TestCaseUtil.java
@@ -16,8 +16,7 @@
 
 package android.test;
 
-import com.google.android.collect.Lists;
-
+import java.util.ArrayList;
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
@@ -44,7 +43,7 @@
     @SuppressWarnings("unchecked")
     public static List<String> getTestCaseNames(Test test, boolean flatten) {
         List<Test> tests = (List<Test>) getTests(test, flatten);
-        List<String> testCaseNames = Lists.newArrayList();
+        List<String> testCaseNames = new ArrayList<>();
         for (Test aTest : tests) {
             testCaseNames.add(getTestName(aTest));
         }
@@ -57,7 +56,7 @@
 
     private static List<? extends Test> getTests(Test test, boolean flatten,
             Set<Class<?>> seen) {
-        List<Test> testCases = Lists.newArrayList();
+        List<Test> testCases = new ArrayList<>();
         if (test != null) {
 
             Test workingTest = null;
diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java
index beecc6f..ff045c3 100644
--- a/test-runner/src/android/test/TestRunner.java
+++ b/test-runner/src/android/test/TestRunner.java
@@ -32,7 +32,6 @@
 import junit.framework.TestListener;
 import junit.framework.Test;
 import junit.framework.TestResult;
-import com.google.android.collect.Lists;
 
 /**
  * Support class that actually runs a test. Android uses this class,
@@ -54,7 +53,7 @@
 
     private int mMode = REGRESSION;
 
-    private List<Listener> mListeners = Lists.newArrayList();
+    private List<Listener> mListeners = new ArrayList<>();
     private int mPassed;
     private int mFailed;
 
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index d8e0977..a70152c 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -23,8 +23,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 
-import com.google.android.collect.Maps;
-
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -67,7 +66,7 @@
      */
     public MockContentResolver(Context context) {
         super(context);
-        mProviders = Maps.newHashMap();
+        mProviders = new HashMap<>();
     }
 
     /**
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 3b920cf..cf6936b 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -21,7 +21,6 @@
 import android.test.TestCaseUtil;
 import android.util.Log;
 import com.android.internal.util.Predicate;
-import com.google.android.collect.Lists;
 import static android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME;
 import static android.test.suitebuilder.TestPredicates.REJECT_SUPPRESSED;
 
@@ -69,7 +68,7 @@
     public TestSuiteBuilder(String name, ClassLoader classLoader) {
         this.suiteName = name;
         this.testGrouping.setClassLoader(classLoader);
-        this.testCases = Lists.newArrayList();
+        this.testCases = new ArrayList<>();
         addRequirements(REJECT_SUPPRESSED);
     }
 
diff --git a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
index 0574704..6723548 100644
--- a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
@@ -19,8 +19,7 @@
 import android.test.mock.MockContext;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.google.android.collect.Lists;
-
+import java.util.ArrayList;
 import junit.framework.TestCase;
 import junit.framework.AssertionFailedError;
 import junit.framework.Test;
@@ -140,7 +139,7 @@
     public void testSetTestClassWithTestSuiteProvider() throws Exception {
         mAndroidTestRunner.setTestClassName(SampleTestSuiteProvider.class.getName(), null);
         List<TestCase> testCases = mAndroidTestRunner.getTestCases();
-        List<String> testNames = Lists.newArrayList();
+        List<String> testNames = new ArrayList<>();
         for (TestCase testCase : testCases) {
             testNames.add(testCase.getName());
         }
@@ -152,7 +151,7 @@
     public void testSetTestClassWithTestSuite() throws Exception {
         mAndroidTestRunner.setTestClassName(SampleTestSuite.class.getName(), null);
         List<TestCase> testCases = mAndroidTestRunner.getTestCases();
-        List<String> testNames = Lists.newArrayList();
+        List<String> testNames = new ArrayList<>();
         for (TestCase testCase : testCases) {
             testNames.add(testCase.getName());
         }
@@ -163,7 +162,7 @@
         String testMethodName = "testTwo";
         mAndroidTestRunner.setTestClassName(TwoTestTestCase.class.getName(), testMethodName);
         List<TestCase> testCases = mAndroidTestRunner.getTestCases();
-        List<String> testNames = Lists.newArrayList();
+        List<String> testNames = new ArrayList<>();
         for (TestCase testCase : testCases) {
             testNames.add(testCase.getName());
         }
@@ -255,7 +254,7 @@
     }
 
     private static class TestListenerStub implements TestListener {
-        List<String> testNames = Lists.newArrayList();
+        List<String> testNames = new ArrayList<>();
 
         public void addError(Test test, Throwable t) {
         }
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
new file mode 100644
index 0000000..9fcd1b5
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED;
+import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED;
+import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.test.BroadcastInterceptingContext;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TetheringConfigurationTest {
+    @Mock private Context mContext;
+    @Mock private TelephonyManager mTelephonyManager;
+    @Mock private Resources mResources;
+    private Context mMockContext;
+    private boolean mHasTelephonyManager;
+
+    private class MockContext extends BroadcastInterceptingContext {
+        MockContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public Resources getResources() { return mResources; }
+
+        @Override
+        public Object getSystemService(String name) {
+            if (Context.TELEPHONY_SERVICE.equals(name)) {
+                return mHasTelephonyManager ? mTelephonyManager : null;
+            }
+            return super.getSystemService(name);
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
+                .thenReturn(new String[0]);
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
+                .thenReturn(new String[0]);
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
+                .thenReturn(new String[]{ "test_wlan\\d" });
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
+                .thenReturn(new String[0]);
+        mMockContext = new MockContext(mContext);
+    }
+
+    @Test
+    public void testDunFromTelephonyManagerMeansDun() {
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI});
+        mHasTelephonyManager = true;
+        when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED);
+
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+        assertTrue(cfg.isDunRequired);
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
+        assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
+        assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
+        // Just to prove we haven't clobbered Wi-Fi:
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+    }
+
+    @Test
+    public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI});
+        mHasTelephonyManager = true;
+        when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED);
+
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+        assertFalse(cfg.isDunRequired);
+        assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
+        // Just to prove we haven't clobbered Wi-Fi:
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+    }
+
+    @Test
+    public void testDunFromUpstreamConfigMeansDun() {
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI});
+        mHasTelephonyManager = false;
+        when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+        assertTrue(cfg.isDunRequired);
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
+        // Just to prove we haven't clobbered Wi-Fi:
+        assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+    }
+}