Merge "set translatable as false for config file"
diff --git a/ecc/README.md b/ecc/README.md
index ef795d5..b5dc538 100644
--- a/ecc/README.md
+++ b/ecc/README.md
@@ -6,43 +6,28 @@
 
 gen_eccdata.sh
   - A script to launch the newest conversion toolset to convert
-    input/eccdata.txt into output/eccdata, and invoke compatibility
-    verification tools of earlier versions of toolsets.
+    input/eccdata.txt into output/eccdata.
 
 input/eccdata.txt
   - A text file in ProtoBuf text format which contains all known ECC data.
-    This file shall be compatible with the last version of format toolset,
-    but may not be compatible with all earlier versions.
 
 output/eccdata
-  - The binary file generated from input files, with the last version of
-    format toolset. This file shall be compatible with all earlier versions.
+  - The binary file generated from input files.
 
 conversion_toolset_v*
-  - Contains format definitions, converting tools and verification tools of
-    one version of ECC data format.
+  - Contains format definitions and converting tools.
 
 proto
   - A symbolic link references to protobuf folder of the newest version of
     conversion toolsets. It's used in Android.mk.
 
-Conversion Toolset
-===================
-
-Every version of conversion toolset shall include at least:
-  - A script to generate eccdata from a known version of input/eccdata.txt.
-  - A script to verify compatibility of output/eccdata generated by any
-    newer version of format toolset.
-
-The output/eccdata generated by a version of conversion toolset shall be
-able to pass compatibility verifications of all previous versions of format
-toolset.
-
 Updating ECC database
 ===================
 Steps to update the ECC database:
 1. Edit input/eccdata.txt
 2. Source and launch
 3. Run gen_eccdata.sh
-The database file "output/eccdata" should be updated.
-
+4. Make TeleService
+5. Push TeleService.apk to system/priv-app/TeleService
+6. Reboot device
+7. run 'atest TeleServiceTests:IsoToEccProtobufRepositoryTest#testEccDataContent'
diff --git a/ecc/conversion_toolset_v1/env.sh b/ecc/conversion_toolset_v1/env.sh
index 23d9f10..534c807 100644
--- a/ecc/conversion_toolset_v1/env.sh
+++ b/ecc/conversion_toolset_v1/env.sh
@@ -20,19 +20,3 @@
 PROTOBUF_DIR="${LOCAL_TOOLSET_DIR}/proto"
 PROTOBUF_FILE="${PROTOBUF_DIR}/protobuf_ecc_data.proto"
 RAW_DATA="${INTERMEDIATE_DIR}/eccdata.raw"
-
-read -d "" PYTHON_COMMAND << END || :
-${ANDROID_BUILD_TOP}/prebuilts/python/${KERNEL}-x86/2.7.5/bin/python
-END
-PYTHONPATH="${PYTHONPATH}:${INTERMEDIATE_DIR}"
-PYTHONPATH="${PYTHONPATH}:${ANDROID_BUILD_TOP}/external/nanopb-c/generator/"
-
-if ! [ -x "${PYTHON_COMMAND}" ] ; then
-  echo "Missing ${PYTHON_COMMAND}." 1>&2
-  exit 1
-fi
-
-"${PROTOC_COMMAND}" \
-  --python_out="${INTERMEDIATE_DIR}" \
-  --proto_path="${PROTOBUF_DIR}" \
-  "${PROTOBUF_FILE}"
diff --git a/ecc/conversion_toolset_v1/gen_eccdata.sh b/ecc/conversion_toolset_v1/gen_eccdata.sh
index 8dd751f..1efac37 100644
--- a/ecc/conversion_toolset_v1/gen_eccdata.sh
+++ b/ecc/conversion_toolset_v1/gen_eccdata.sh
@@ -18,19 +18,12 @@
 LOCAL_TOOLSET_DIR="${ECC_ROOT}/conversion_toolset_v1"
 source "${LOCAL_TOOLSET_DIR}/env.sh"
 
+echo "Converting eccdata..."
 ${ANDROID_BUILD_TOP}/prebuilts/tools/linux-x86_64/protoc/bin/protoc \
   --encode=ecc.AllInfo proto/protobuf_ecc_data.proto \
   < "${INPUT_DATA}" > "${RAW_DATA}"
 
-echo
-echo "Starting strict verification"
-"${PYTHON_COMMAND}" -B \
-  "${LOCAL_TOOLSET_DIR}/verify_protobuf_compatibility.py" \
-  --input="${RAW_DATA}" --strict
-echo "Passed strict verification"
-
-echo
-echo "Compressing and encoding eccdata"
+echo "Compressing eccdata..."
 gzip -c < "${RAW_DATA}" > "${OUTPUT_DATA}"
-echo "Done"
 
+echo "Done"
diff --git a/ecc/conversion_toolset_v1/proto/Android.bp b/ecc/conversion_toolset_v1/proto/Android.bp
new file mode 100644
index 0000000..7d6cce4
--- /dev/null
+++ b/ecc/conversion_toolset_v1/proto/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 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.
+
+java_library_static {
+    name: "ecc-protos-lite",
+    proto: {
+        type: "nano",
+        output_params: [
+            "store_unknown_fields=true",
+            "enum_style=java",
+        ],
+    },
+    srcs: ["protobuf_ecc_data.proto"],
+    no_framework_libs: true,
+    jarjar_rules: "jarjar-rules.txt",
+    java_version: "1.8",
+}
\ No newline at end of file
diff --git a/ecc/conversion_toolset_v1/proto/jarjar-rules.txt b/ecc/conversion_toolset_v1/proto/jarjar-rules.txt
new file mode 100644
index 0000000..98ac044
--- /dev/null
+++ b/ecc/conversion_toolset_v1/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.nano.** com.android.phone.ecc.nano.@1
\ No newline at end of file
diff --git a/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh b/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh
deleted file mode 100644
index 8686722..0000000
--- a/ecc/conversion_toolset_v1/verify_eccdata_compatibility.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-set -o errexit
-
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_TOOLSET_DIR="${ECC_ROOT}/conversion_toolset_v1"
-source "${LOCAL_TOOLSET_DIR}/env.sh"
-
-echo "Starting compatibility verification v1"
-echo "Decoding and decompressing eccdata"
-gunzip -c < "${OUTPUT_DATA}" > "${RAW_DATA}"
-${PYTHON_COMMAND} -B \
-  "${LOCAL_TOOLSET_DIR}/verify_protobuf_compatibility.py" \
-  --input="${RAW_DATA}"
-echo "Passed compatibility verification v1"
-
diff --git a/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py b/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py
deleted file mode 100644
index bc707eb..0000000
--- a/ecc/conversion_toolset_v1/verify_protobuf_compatibility.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/python -B
-
-# Copyright 2018 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.
-
-# Notice:
-# - verify_eccdata_strict.py: Verify data which is generated by this
-# version of this toolset.
-# - verify_eccdata_compatibility.py: Verify data which is generated by any
-# newer version of this tool set for ensuring backward compatibility.
-
-import sys
-import argparse
-import protobuf_ecc_data_pb2
-
-parser = argparse.ArgumentParser()
-parser.add_argument("--input", required=True)
-parser.add_argument("--strict", action="store_true")
-args = parser.parse_args()
-
-all_ecc_info = protobuf_ecc_data_pb2.AllInfo()
-
-with open(args.input, "rb") as ecc_data_source_file:
-  all_ecc_info.ParseFromString(ecc_data_source_file.read())
-
-if (args.strict):
-  print("Verify in strict mode")
-
-assert all_ecc_info.HasField("revision")
-assert all_ecc_info.revision > 0
-assert len(all_ecc_info.countries) > 0
-
-loaded_iso = []
-for country_info in all_ecc_info.countries:
-  assert country_info.HasField("iso_code")
-  assert len(country_info.iso_code) > 0
-  assert country_info.iso_code == country_info.iso_code.strip().upper()
-  assert country_info.iso_code not in loaded_iso
-  loaded_iso.append(country_info.iso_code)
-  assert country_info.HasField("ecc_fallback")
-  assert len(country_info.ecc_fallback) > 0
-
-  if len(country_info.eccs) > 0:
-    loaded_phone_number = []
-    for ecc_info in country_info.eccs:
-      assert ecc_info.HasField("phone_number")
-      phone_number = ecc_info.phone_number.strip()
-      assert len(phone_number) > 0
-      assert phone_number not in loaded_phone_number
-      loaded_phone_number.append(phone_number)
-
-      if (args.strict):
-        assert len(ecc_info.types) > 0
-        loaded_types = []
-        for ecc_type in ecc_info.types:
-          assert ecc_type == protobuf_ecc_data_pb2.EccInfo.POLICE or \
-              ecc_type == protobuf_ecc_data_pb2.EccInfo.AMBULANCE or \
-              ecc_type == protobuf_ecc_data_pb2.EccInfo.FIRE
-          assert ecc_type not in loaded_types
-          loaded_types.append(ecc_type)
-      else:
-        # For forward compatibility, ecc_info.types could be null if a phone
-        # number contains only new types which is not defined now. Just leave
-        # a warning message for this case.
-        if len(ecc_info.types) == 0:
-          print("WARNING: No recognizable type for " + \
-              country_info.iso_code + " - " + ecc_info.phone_number)
-        else:
-          loaded_types = []
-          for ecc_type in ecc_info.types:
-            assert ecc_type not in loaded_types
-            loaded_types.append(ecc_type)
-  elif (args.strict):
-    print("Warning: Empty ecc list for country " + country_info.iso_code)
diff --git a/ecc/gen_eccdata.sh b/ecc/gen_eccdata.sh
index 5cf52de..4f3a097 100755
--- a/ecc/gen_eccdata.sh
+++ b/ecc/gen_eccdata.sh
@@ -53,15 +53,8 @@
 source "${TOOLSET_DIR}/gen_eccdata.sh"
 echo
 
-# Check compatibility with every previous version
-rm -rf "${INTERMEDIATE_DIR}/*"
-source ${ECC_ROOT}/conversion_toolset_v1/verify_eccdata_compatibility.sh
-#rm -rf "${INTERMEDIATE_DIR}/*"
-#source ${ECC_ROOT}/conversion_toolset_v2/verify_eccdata_compatibility.sh
-#rm -rf "${INTERMEDIATE_DIR}/*"
-#source ${ECC_ROOT}/conversion_toolset_v3/verify_eccdata_compatibility.sh
-#...
-
-echo
-echo "Passed all compatibility verification!"
-
+echo "To verify data compatibility:"
+echo "  1. make TeleService"
+echo "  2. push TeleService.apk to system/priv-app/TeleService"
+echo "  3. reboot device"
+echo "  4. run 'atest TeleServiceTests:IsoToEccProtobufRepositoryTest#testEccDataContent'"
diff --git a/res/values/config.xml b/res/values/config.xml
index 7dc0d52..b1c1607 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -235,6 +235,9 @@
     <!-- Flag indicating whether the device supports RTT (real-time text) -->
     <bool name="config_support_rtt">false</bool>
 
+    <!-- The package name for the platform number verification supplier app. -->
+    <string name="platform_number_verification_package" translatable="false"></string>
+
     <!-- Flag indicating whether a system app can use video calling fallback if carrier video
          calling is not available. -->
     <bool name="config_support_video_calling_fallback">true</bool>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b3889dd..8fd194a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -51,7 +51,7 @@
     <!-- Label for "cancel" button on the MMI dialog -->
     <string name="cancel">Cancel</string>
     <!-- Toast string displayed to user if the input in MMI dialog is < 1 or > 160 -->
-    <string name="enter_input">USSD message must be between <xliff:g id="min_len" >%d</xliff:g> and <xliff:g id="max_len" >%d</xliff:g> characters. Please try again.</string>
+    <string name="enter_input">USSD message must be between <xliff:g id="min_len" >%1$d</xliff:g> and <xliff:g id="max_len" >%2$d</xliff:g> characters. Please try again.</string>
 
     <!-- Label for "Manage conference call" panel [CHAR LIMIT=40] -->
     <string name="manageConferenceLabel">Manage conference call</string>
diff --git a/res/xml/telephony_injection.xml b/res/xml/telephony_injection.xml
new file mode 100644
index 0000000..2af425c
--- /dev/null
+++ b/res/xml/telephony_injection.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2018 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: customized component factory to inject,
+        e.g. "example.package.exampleTelephonyComponentFactory"
+     jar: jar path to customized jar which contains exampleTelephonyComponentFactory to inject, and
+     "/system/framework/" should be the target directory.
+        e.g. "/system/framework/eg-telephony-common.jar"
+-->
+<injection package=""
+           jar="">
+    <components>
+        <!-- Components use injected component factory,
+            e.g. com.android.internal.telephony.ServiceStateTracker
+        -->
+        <!--<component>com.example.componentA</component>-->
+        <!--<component>com.example.componentB</component>-->
+    </components>
+</injection>
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index e2f4fee..8d2d71f 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -35,6 +35,7 @@
 import android.provider.Settings;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
@@ -303,7 +304,7 @@
         if (mImsMgr.isVtEnabledByPlatform() && mImsMgr.isVtProvisionedOnDevice()
                 && (carrierConfig.getBoolean(
                         CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
-                || mPhone.mDcTracker.isDataEnabled())) {
+                || mPhone.getDcTracker(TransportType.WWAN).isDataEnabled())) {
             boolean currentValue =
                     mImsMgr.isEnhanced4gLteModeSettingEnabledByUser()
                     ? mImsMgr.isVtEnabledByUser() : false;
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 15c5780..1e9e286 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -526,17 +526,17 @@
         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
                 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-        // Include subId extra only if SIM records are loaded
+        // Include subId/carrier id extra only if SIM records are loaded
         TelephonyManager telephonyManager = TelephonyManager.from(mContext);
         int simApplicationState = telephonyManager.getSimApplicationState();
         if (addSubIdExtra && (simApplicationState != TelephonyManager.SIM_STATE_UNKNOWN
                 && simApplicationState != TelephonyManager.SIM_STATE_NOT_READY)) {
             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
+            intent.putExtra(TelephonyManager.EXTRA_PRECISE_CARRIER_ID,
+                    getPreciseCarrierIdForPhoneId(phoneId));
+            intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, getCarrierIdForPhoneId(phoneId));
         }
         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
-        intent.putExtra(TelephonyManager.EXTRA_PRECISE_CARRIER_ID,
-                getPreciseCarrierIdForPhoneId(phoneId));
-        intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, getCarrierIdForPhoneId(phoneId));
         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
         mHasSentConfigChange[phoneId] = true;
     }
diff --git a/src/com/android/phone/NetworkSelectListPreference.java b/src/com/android/phone/NetworkSelectListPreference.java
index 9af1c77..df3f44a 100644
--- a/src/com/android/phone/NetworkSelectListPreference.java
+++ b/src/com/android/phone/NetworkSelectListPreference.java
@@ -103,7 +103,8 @@
         new AsyncTask<Void, Void, List<String>>() {
             @Override
             protected List<String> doInBackground(Void... voids) {
-                return Arrays.asList(telephonyManager.getForbiddenPlmns());
+                String[] forbiddenPlmns = telephonyManager.getForbiddenPlmns();
+                return forbiddenPlmns != null ? Arrays.asList(forbiddenPlmns) : null;
             }
 
             @Override
diff --git a/src/com/android/phone/NetworkSelectSetting.java b/src/com/android/phone/NetworkSelectSetting.java
index 9b905b4..d9731be 100644
--- a/src/com/android/phone/NetworkSelectSetting.java
+++ b/src/com/android/phone/NetworkSelectSetting.java
@@ -166,7 +166,8 @@
         new AsyncTask<Void, Void, List<String>>() {
             @Override
             protected List<String> doInBackground(Void... voids) {
-                return Arrays.asList(mTelephonyManager.getForbiddenPlmns());
+                String[] forbiddenPlmns = mTelephonyManager.getForbiddenPlmns();
+                return forbiddenPlmns != null ? Arrays.asList(forbiddenPlmns) : null;
             }
 
             @Override
diff --git a/src/com/android/phone/NumberVerificationManager.java b/src/com/android/phone/NumberVerificationManager.java
new file mode 100644
index 0000000..9ec16f8
--- /dev/null
+++ b/src/com/android/phone/NumberVerificationManager.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.telephony.NumberVerificationCallback;
+import android.telephony.PhoneNumberRange;
+import android.telephony.ServiceState;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.INumberVerificationCallback;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+
+/**
+ * Singleton for managing the call based number verification requests.
+ */
+public class NumberVerificationManager {
+    interface PhoneListSupplier {
+        Phone[] getPhones();
+    }
+
+    private static NumberVerificationManager sInstance;
+    private static String sAuthorizedPackageOverride;
+
+    private PhoneNumberRange mCurrentRange;
+    private INumberVerificationCallback mCallback;
+    private final PhoneListSupplier mPhoneListSupplier;
+
+    // We don't really care what thread this runs on, since it's only used for a non-blocking
+    // timeout.
+    private Handler mHandler;
+
+    NumberVerificationManager(PhoneListSupplier phoneListSupplier) {
+        mPhoneListSupplier = phoneListSupplier;
+        mHandler = new Handler(Looper.getMainLooper());
+    }
+
+    private NumberVerificationManager() {
+        this(PhoneFactory::getPhones);
+    }
+
+    /**
+     * Check whether the incoming call matches one of the active filters. If so, call the callback
+     * that says that the number has been successfully verified.
+     * @param number A phone number
+     * @return true if the number matches, false otherwise
+     */
+    public synchronized boolean checkIncomingCall(String number) {
+        if (mCurrentRange == null || mCallback == null) {
+            return false;
+        }
+
+        if (mCurrentRange.matches(number)) {
+            mCurrentRange = null;
+            try {
+                mCallback.onCallReceived(number);
+                return true;
+            } catch (RemoteException e) {
+                Log.w(NumberVerificationManager.class.getSimpleName(),
+                        "Remote exception calling verification complete callback");
+                // Intercept the call even if there was a remote exception -- it's still going to be
+                // a strange call from a robot number
+                return true;
+            } finally {
+                mCallback = null;
+            }
+        }
+        return false;
+    }
+
+    synchronized void requestVerification(PhoneNumberRange numberRange,
+            INumberVerificationCallback callback, long timeoutMillis) {
+        if (!checkNumberVerificationFeasibility(callback)) {
+            return;
+        }
+
+        mCallback = callback;
+        mCurrentRange = numberRange;
+
+        mHandler.postDelayed(() -> {
+            synchronized (NumberVerificationManager.this) {
+                // Check whether the verification finished already -- if so, don't call anything.
+                if (mCallback != null && mCurrentRange != null) {
+                    try {
+                        mCallback.onVerificationFailed(NumberVerificationCallback.REASON_TIMED_OUT);
+                    } catch (RemoteException e) {
+                        Log.w(NumberVerificationManager.class.getSimpleName(),
+                                "Remote exception calling verification error callback");
+                    }
+                    mCallback = null;
+                    mCurrentRange = null;
+                }
+            }
+        }, timeoutMillis);
+    }
+
+    private boolean checkNumberVerificationFeasibility(INumberVerificationCallback callback) {
+        int reason = -1;
+        try {
+            if (mCurrentRange != null || mCallback != null) {
+                reason = NumberVerificationCallback.REASON_CONCURRENT_REQUESTS;
+                return false;
+            }
+            boolean doesAnyPhoneHaveRoomForIncomingCall = false;
+            boolean isAnyPhoneVoiceRegistered = false;
+            for (Phone phone : mPhoneListSupplier.getPhones()) {
+                // abort if any phone is in an emergency call or ecbm
+                if (phone.isInEmergencyCall()) {
+                    reason = NumberVerificationCallback.REASON_IN_EMERGENCY_CALL;
+                    return false;
+                }
+                if (phone.isInEcm()) {
+                    reason = NumberVerificationCallback.REASON_IN_ECBM;
+                    return false;
+                }
+
+                // make sure at least one phone is registered for voice
+                if (phone.getServiceState().getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+                    isAnyPhoneVoiceRegistered = true;
+                }
+                // make sure at least one phone has room for an incoming call.
+                if (phone.getRingingCall().getState() == Call.State.IDLE
+                        && (phone.getForegroundCall().getState() == Call.State.IDLE
+                        || phone.getBackgroundCall().getState() == Call.State.IDLE)) {
+                    doesAnyPhoneHaveRoomForIncomingCall = true;
+                }
+            }
+            if (!isAnyPhoneVoiceRegistered) {
+                reason = NumberVerificationCallback.REASON_NETWORK_NOT_AVAILABLE;
+                return false;
+            }
+            if (!doesAnyPhoneHaveRoomForIncomingCall) {
+                reason = NumberVerificationCallback.REASON_TOO_MANY_CALLS;
+                return false;
+            }
+        } finally {
+            if (reason >= 0) {
+                try {
+                    callback.onVerificationFailed(reason);
+                } catch (RemoteException e) {
+                    Log.w(NumberVerificationManager.class.getSimpleName(),
+                            "Remote exception calling verification error callback");
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Get the singleton instance of NumberVerificationManager.
+     * @return
+     */
+    public static NumberVerificationManager getInstance() {
+        if (sInstance == null) {
+            sInstance = new NumberVerificationManager();
+        }
+        return sInstance;
+    }
+
+    static String getAuthorizedPackage(Context context) {
+        return !TextUtils.isEmpty(sAuthorizedPackageOverride) ? sAuthorizedPackageOverride :
+                context.getResources().getString(R.string.platform_number_verification_package);
+    }
+
+    /**
+     * Used by shell commands to override the authorized package name for number verification.
+     * @param pkgName
+     */
+    static void overrideAuthorizedPackage(String pkgName) {
+        sAuthorizedPackageOverride = pkgName;
+    }
+}
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 3f679ed..ccbb4d0 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -25,6 +25,7 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.XmlResourceParser;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.Uri;
@@ -46,6 +47,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.util.LocalLog;
 import android.util.Log;
 import android.widget.Toast;
@@ -58,11 +60,11 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SettingsObserver;
 import com.android.internal.telephony.TelephonyCapabilities;
+import com.android.internal.telephony.TelephonyComponentFactory;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons;
 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.phone.common.CallLogAsync;
 import com.android.phone.settings.SettingsConstants;
 import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
 import com.android.services.telephony.sip.SipAccountRegistry;
@@ -281,6 +283,9 @@
         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
 
         if (mCM == null) {
+            // Inject telephony component factory if configured using other jars.
+            XmlResourceParser parser = getResources().getXml(R.xml.telephony_injection);
+            TelephonyComponentFactory.getInstance().injectTheComponentFactory(parser);
             // Initialize the telephony framework
             PhoneFactory.makeDefaultPhones(this);
 
@@ -325,7 +330,7 @@
             // The asynchronous caching will start just after this call.
             callerInfoCache = CallerInfoCache.init(this);
 
-            phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone());
+            phoneMgr = PhoneInterfaceManager.init(this);
 
             configLoader = CarrierConfigLoader.init(this);
 
@@ -713,7 +718,7 @@
         }
 
         DataConnectionReasons reasons = new DataConnectionReasons();
-        boolean dataAllowed = phone.isDataAllowed(reasons);
+        boolean dataAllowed = phone.isDataAllowed(ApnSetting.TYPE_DEFAULT, reasons);
         mDataRoamingNotifLog.log("dataAllowed=" + dataAllowed + ", reasons=" + reasons);
         if (VDBG) Log.v(LOG_TAG, "dataAllowed=" + dataAllowed + ", reasons=" + reasons);
         if (!mNoDataDueToRoaming
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index dfea90c..2f3dd46 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -16,6 +16,8 @@
 
 package com.android.phone;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
 
 import android.Manifest.permission;
@@ -66,6 +68,7 @@
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
 import android.telephony.NetworkScanRequest;
+import android.telephony.PhoneNumberRange;
 import android.telephony.RadioAccessFamily;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
@@ -79,6 +82,7 @@
 import android.telephony.UssdResponse;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.telephony.cdma.CdmaCellLocation;
+import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.gsm.GsmCellLocation;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -105,6 +109,7 @@
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.DefaultPhoneNotifier;
+import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.LocaleTracker;
@@ -237,7 +242,6 @@
     private static PhoneInterfaceManager sInstance;
 
     private PhoneGlobals mApp;
-    private Phone mPhone;
     private CallManager mCM;
     private UserManager mUserManager;
     private AppOpsManager mAppOps;
@@ -362,6 +366,7 @@
             AsyncResult ar;
             UiccCard uiccCard;
             IccAPDUArgument iccArgument;
+            final Phone defaultPhone = getDefaultPhone();
 
             switch (msg.what) {
                 case CMD_HANDLE_USSD_REQUEST: {
@@ -616,7 +621,8 @@
                 case CMD_NV_READ_ITEM:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
-                    mPhone.nvReadItem((Integer) request.argument, onCompleted, request.workSource);
+                    defaultPhone.nvReadItem((Integer) request.argument, onCompleted,
+                            request.workSource);
                     break;
 
                 case EVENT_NV_READ_ITEM_DONE:
@@ -642,7 +648,7 @@
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
                     Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
-                    mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted,
+                    defaultPhone.nvWriteItem(idValue.first, idValue.second, onCompleted,
                             request.workSource);
                     break;
 
@@ -653,7 +659,7 @@
                 case CMD_NV_WRITE_CDMA_PRL:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
-                    mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
+                    defaultPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
                     break;
 
                 case EVENT_NV_WRITE_CDMA_PRL_DONE:
@@ -663,7 +669,7 @@
                 case CMD_RESET_MODEM_CONFIG:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_RESET_MODEM_CONFIG_DONE, request);
-                    mPhone.resetModemConfig(onCompleted);
+                    defaultPhone.resetModemConfig(onCompleted);
                     break;
 
                 case EVENT_RESET_MODEM_CONFIG_DONE:
@@ -709,7 +715,7 @@
                 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
                     request = (MainThreadRequest)msg.obj;
                     onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
-                    mPhone.invokeOemRilRequestRaw((byte[]) request.argument, onCompleted);
+                    defaultPhone.invokeOemRilRequestRaw((byte[]) request.argument, onCompleted);
                     break;
 
                 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
@@ -805,7 +811,7 @@
                 case CMD_GET_MODEM_ACTIVITY_INFO:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_GET_MODEM_ACTIVITY_INFO_DONE, request);
-                    mPhone.getModemActivityInfo(onCompleted, request.workSource);
+                    defaultPhone.getModemActivityInfo(onCompleted, request.workSource);
                     break;
 
                 case EVENT_GET_MODEM_ACTIVITY_INFO_DONE:
@@ -833,7 +839,7 @@
                 case CMD_SET_ALLOWED_CARRIERS:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_SET_ALLOWED_CARRIERS_DONE, request);
-                    mPhone.setAllowedCarriers(
+                    defaultPhone.setAllowedCarriers(
                             (List<CarrierIdentifier>) request.argument,
                             onCompleted, request.workSource);
                     break;
@@ -863,7 +869,7 @@
                 case CMD_GET_ALLOWED_CARRIERS:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_GET_ALLOWED_CARRIERS_DONE, request);
-                    mPhone.getAllowedCarriers(onCompleted, request.workSource);
+                    defaultPhone.getAllowedCarriers(onCompleted, request.workSource);
                     break;
 
                 case EVENT_GET_ALLOWED_CARRIERS_DONE:
@@ -1070,7 +1076,7 @@
                 case CMD_MODEM_REBOOT:
                     request = (MainThreadRequest) msg.obj;
                     onCompleted = obtainMessage(EVENT_RESET_MODEM_CONFIG_DONE, request);
-                    mPhone.rebootModem(onCompleted);
+                    defaultPhone.rebootModem(onCompleted);
                     break;
                 case EVENT_CMD_MODEM_REBOOT_DONE:
                     handleNullReturnEvent(msg, "rebootModem");
@@ -1221,10 +1227,10 @@
      * Initialize the singleton PhoneInterfaceManager instance.
      * This is only done once, at startup, from PhoneApp.onCreate().
      */
-    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
+    /* package */ static PhoneInterfaceManager init(PhoneGlobals app) {
         synchronized (PhoneInterfaceManager.class) {
             if (sInstance == null) {
-                sInstance = new PhoneInterfaceManager(app, phone);
+                sInstance = new PhoneInterfaceManager(app);
             } else {
                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
             }
@@ -1233,22 +1239,26 @@
     }
 
     /** Private constructor; @see init() */
-    private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
+    private PhoneInterfaceManager(PhoneGlobals app) {
         mApp = app;
-        mPhone = phone;
         mCM = PhoneGlobals.getInstance().mCM;
         mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
         mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
         mMainThreadHandler = new MainThreadHandler();
-        mTelephonySharedPreferences =
-                PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
         mSubscriptionController = SubscriptionController.getInstance();
+        mTelephonySharedPreferences =
+                PreferenceManager.getDefaultSharedPreferences(mApp);
         mNetworkScanRequestTracker = new NetworkScanRequestTracker();
         mPhoneConfigurationManager = PhoneConfigurationManager.getInstance();
 
         publish();
     }
 
+    private Phone getDefaultPhone() {
+        Phone thePhone = getPhone(getDefaultSubscription());
+        return (thePhone != null) ? thePhone : PhoneFactory.getDefaultPhone();
+    }
+
     private void publish() {
         if (DBG) log("publish: " + this);
 
@@ -1257,7 +1267,7 @@
 
     private Phone getPhoneFromRequest(MainThreadRequest request) {
         return (request.subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID)
-                ? mPhone : getPhone(request.subId);
+                ? getDefaultPhone() : getPhone(request.subId);
     }
 
     private UiccCard getUiccCardFromRequest(MainThreadRequest request) {
@@ -1715,7 +1725,7 @@
         try {
             final Phone phone = getPhone(subId);
             if (phone != null) {
-                return phone.isDataAllowed();
+                return phone.isDataAllowed(ApnSetting.TYPE_DEFAULT);
             } else {
                 return false;
             }
@@ -1805,10 +1815,10 @@
 
     @Override
     public Bundle getCellLocation(String callingPackage) {
-        mPhone.getContext().getSystemService(AppOpsManager.class)
+        mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!LocationAccessPolicy.canAccessCellLocation(mPhone.getContext(),
-                callingPackage, Binder.getCallingUid(), Binder.getCallingPid(), true)) {
+        if (!LocationAccessPolicy.canAccessCellLocation(mApp, callingPackage,
+                Binder.getCallingUid(), Binder.getCallingPid(), true)) {
             return null;
         }
 
@@ -1908,8 +1918,8 @@
      */
     private int getTargetSdk(String packageName) {
         try {
-            final ApplicationInfo ai =
-                    mPhone.getContext().getPackageManager().getApplicationInfo(packageName, 0);
+            final ApplicationInfo ai = mApp.getPackageManager().getApplicationInfo(
+                            packageName, 0);
             if (ai != null) return ai.targetSdkVersion;
         } catch (PackageManager.NameNotFoundException unexpected) {
         }
@@ -1957,9 +1967,9 @@
 
     @Override
     public List<CellInfo> getAllCellInfo(String callingPackage) {
-        mPhone.getContext().getSystemService(AppOpsManager.class)
+        mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!LocationAccessPolicy.canAccessCellLocation(mPhone.getContext(),
+        if (!LocationAccessPolicy.canAccessCellLocation(mApp,
                 callingPackage, Binder.getCallingUid(), Binder.getCallingPid(), true)) {
             return null;
         }
@@ -2000,10 +2010,10 @@
 
     private void requestCellInfoUpdateInternal(
             int subId, ICellInfoCallback cb, String callingPackage, WorkSource workSource) {
-        mPhone.getContext().getSystemService(AppOpsManager.class)
+        mApp.getSystemService(AppOpsManager.class)
                 .checkPackage(Binder.getCallingUid(), callingPackage);
-        if (!LocationAccessPolicy.canAccessCellLocation(mPhone.getContext(),
-                callingPackage, Binder.getCallingUid(), Binder.getCallingPid(), true)) {
+        if (!LocationAccessPolicy.canAccessCellLocation(mApp, callingPackage,
+                Binder.getCallingUid(), Binder.getCallingPid(), true)) {
             return;
         }
 
@@ -2020,7 +2030,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            mPhone.setCellInfoListRate(rateInMillis, workSource);
+            getDefaultPhone().setCellInfoListRate(rateInMillis, workSource);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2063,6 +2073,7 @@
         if (phone == null) {
             return null;
         }
+
         int subId = phone.getSubId();
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                 mApp, subId, callingPackage, "getMeidForSlot")) {
@@ -2131,17 +2142,6 @@
     }
 
     @Override
-    public int getSubscriptionMNOCarrierId(int subId) {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final Phone phone = getPhone(subId);
-            return phone == null ? TelephonyManager.UNKNOWN_CARRIER_ID : phone.getMNOCarrierId();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
     public int getSubscriptionPreciseCarrierId(int subId) {
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -2165,7 +2165,10 @@
     }
 
     @Override
-    public int getCarrierIdFromMccMnc(int slotIndex, String mccmnc) {
+    public int getCarrierIdFromMccMnc(int slotIndex, String mccmnc, boolean isSubscriptionMccMnc) {
+        if (!isSubscriptionMccMnc) {
+            enforceReadPrivilegedPermission("getCarrierIdFromMccMnc");
+        }
         final Phone phone = PhoneFactory.getPhone(slotIndex);
         if (phone == null) {
             return TelephonyManager.UNKNOWN_CARRIER_ID;
@@ -2201,8 +2204,7 @@
     }
 
     private void enforceConnectivityInternalPermission() {
-        mApp.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
                 "ConnectivityService");
     }
 
@@ -2343,9 +2345,10 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final Phone phone = getPhone(subId);
-            if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA && phone != null) {
+            if (phone != null && phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
                 return phone.getLine1Number();
             } else {
+                loge("getCdmaMdn: no phone found. Invalid subId: " + subId);
                 return null;
             }
         } finally {
@@ -2374,13 +2377,37 @@
         }
     }
 
+    @Override
+    public void requestNumberVerification(PhoneNumberRange range, long timeoutMillis,
+            INumberVerificationCallback callback, String callingPackage) {
+        if (mApp.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+                != PERMISSION_GRANTED) {
+            throw new SecurityException("Caller must hold the MODIFY_PHONE_STATE permission");
+        }
+        mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+
+        String authorizedPackage = NumberVerificationManager.getAuthorizedPackage(mApp);
+        if (!TextUtils.equals(callingPackage, authorizedPackage)) {
+            throw new SecurityException("Calling package must be configured in the device config");
+        }
+
+        if (range == null) {
+            throw new NullPointerException("Range must be non-null");
+        }
+
+        timeoutMillis = Math.min(timeoutMillis,
+                TelephonyManager.MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS);
+
+        NumberVerificationManager.getInstance().requestVerification(range, callback, timeoutMillis);
+    }
+
     /**
      * Returns true if CDMA provisioning needs to run.
      */
     public boolean needsOtaServiceProvisioning() {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return mPhone.needsOtaServiceProvisioning();
+            return getDefaultPhone().needsOtaServiceProvisioning();
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2406,7 +2433,7 @@
     @Override
     public Bundle getVisualVoicemailSettings(String callingPackage, int subId) {
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        String systemDialer = TelecomManager.from(mPhone.getContext()).getSystemDialerPackage();
+        String systemDialer = TelecomManager.from(mApp).getSystemDialerPackage();
         if (!TextUtils.equals(callingPackage, systemDialer)) {
             throw new SecurityException("caller must be system dialer");
         }
@@ -2417,7 +2444,7 @@
             if (phoneAccountHandle == null) {
                 return null;
             }
-            return VisualVoicemailSettingsUtil.dump(mPhone.getContext(), phoneAccountHandle);
+            return VisualVoicemailSettingsUtil.dump(mApp, phoneAccountHandle);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2433,8 +2460,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            return RemoteVvmTaskManager
-                    .getRemotePackage(mPhone.getContext(), subId).getPackageName();
+            return RemoteVvmTaskManager.getRemotePackage(mApp, subId).getPackageName();
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2448,7 +2474,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             VisualVoicemailSmsFilterConfig.enableVisualVoicemailSmsFilter(
-                    mPhone.getContext(), callingPackage, subId, settings);
+                    mApp, callingPackage, subId, settings);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2461,7 +2487,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             VisualVoicemailSmsFilterConfig.disableVisualVoicemailSmsFilter(
-                    mPhone.getContext(), callingPackage, subId);
+                    mApp, callingPackage, subId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2475,7 +2501,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             return VisualVoicemailSmsFilterConfig.getVisualVoicemailSmsFilterSettings(
-                    mPhone.getContext(), callingPackage, subId);
+                    mApp, callingPackage, subId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2488,7 +2514,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             return VisualVoicemailSmsFilterConfig.getActiveVisualVoicemailSmsFilterSettings(
-                    mPhone.getContext(), subId);
+                    mApp, subId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2599,17 +2625,14 @@
     }
 
     /**
-     * Returns the unread count of voicemails
-     */
-    public int getVoiceMessageCount() {
-        return getVoiceMessageCountForSubscriber(getDefaultSubscription());
-    }
-
-    /**
      * Returns the unread count of voicemails for a subId
      */
     @Override
-    public int getVoiceMessageCountForSubscriber( int subId) {
+    public int getVoiceMessageCountForSubscriber(int subId, String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                mApp, subId, callingPackage, "getVoiceMessageCountForSubscriber")) {
+            return 0;
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
             final Phone phone = getPhone(subId);
@@ -2645,8 +2668,10 @@
      */
     @Override
     public void sendDialerSpecialCode(String callingPackage, String inputCode) {
+        final Phone defaultPhone = getDefaultPhone();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        String defaultDialer = TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage();
+        String defaultDialer = TelecomManager.from(defaultPhone.getContext())
+                .getDefaultDialerPackage();
         if (!TextUtils.equals(callingPackage, defaultDialer)) {
             TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
                     getDefaultSubscription(), "sendDialerSpecialCode");
@@ -2654,7 +2679,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            mPhone.sendDialerSpecialCode(inputCode);
+            defaultPhone.sendDialerSpecialCode(inputCode);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2697,7 +2722,7 @@
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
-            ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
+            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .addRegistrationCallbackForSubscription(c, subId);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -2709,7 +2734,7 @@
         enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         Binder.withCleanCallingIdentity(() ->
-                ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
+                ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                         .removeRegistrationCallbackForSubscription(c, subId));
     }
 
@@ -2720,7 +2745,7 @@
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
-            ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
+            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .addCapabilitiesCallbackForSubscription(c, subId);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -2732,7 +2757,7 @@
         enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         Binder.withCleanCallingIdentity(() ->
-                ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
+                ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                         .removeCapabilitiesCallbackForSubscription(c, subId));
     }
 
@@ -2742,7 +2767,7 @@
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).queryMmTelCapability(capability, regTech);
         } catch (ImsException e) {
             Log.w(LOG_TAG, "IMS isCapable - service unavailable: " + e.getMessage());
@@ -2771,7 +2796,7 @@
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).isEnhanced4gLteModeSettingEnabledByUser();
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -2785,7 +2810,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
+            ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).setEnhanced4gLteModeSetting(isEnabled);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2798,7 +2823,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).isVtEnabledByUser();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2812,8 +2837,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
-                    getSlotIndexOrException(subId)).setVtSetting(isEnabled);
+            ImsManager.getInstance(mApp, getSlotIndexOrException(subId)).setVtSetting(isEnabled);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2825,7 +2849,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).isWfcEnabledByUser();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2839,8 +2863,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
-                    getSlotIndexOrException(subId)).setWfcSetting(isEnabled);
+            ImsManager.getInstance(mApp, getSlotIndexOrException(subId)).setWfcSetting(isEnabled);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2852,7 +2875,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).isWfcRoamingEnabledByUser();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2866,7 +2889,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
+            ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).setWfcRoamingSetting(isEnabled);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2880,7 +2903,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
+            ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).setWfcNonPersistent(isCapable, mode);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2893,7 +2916,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).getWfcMode(false /*isRoaming*/);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2907,7 +2930,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
+            ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).setWfcMode(mode, false /*isRoaming*/);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2920,7 +2943,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).getWfcMode(true /*isRoaming*/);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2934,7 +2957,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
+            ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).setWfcMode(mode, true /*isRoaming*/);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2948,7 +2971,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(),
+            ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).setRttEnabled(isEnabled);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2961,7 +2984,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(),
+            return ImsManager.getInstance(mApp,
                     getSlotIndexOrException(subId)).isTtyOnVoLteCapable();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2974,7 +2997,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
+            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .getConfigInterface().addConfigCallback(callback);
         } catch (ImsException e) {
             throw new IllegalArgumentException(e.getMessage());
@@ -2989,7 +3012,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
+            ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
                     .getConfigInterface().removeConfigCallback(callback);
         } catch (ImsException e) {
             throw new IllegalArgumentException(e.getMessage());
@@ -3004,8 +3027,8 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
-                    .getConfigInterface().getConfigInt(key);
+            return ImsManager.getInstance(mApp,
+                    getSlotIndexOrException(subId)).getConfigInterface().getConfigInt(key);
         } catch (ImsException e) {
             throw new IllegalArgumentException(e.getMessage());
         } finally {
@@ -3019,8 +3042,8 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
-                    .getConfigInterface().getConfigString(key);
+            return ImsManager.getInstance(mApp,
+                    getSlotIndexOrException(subId)).getConfigInterface().getConfigString(key);
         } catch (ImsException e) {
             throw new IllegalArgumentException(e.getMessage());
         } finally {
@@ -3035,8 +3058,8 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
-                    .getConfigInterface().setConfig(key, value);
+            return ImsManager.getInstance(mApp,
+                    getSlotIndexOrException(subId)).getConfigInterface().setConfig(key, value);
         } catch (ImsException e) {
             throw new IllegalArgumentException(e.getMessage());
         } finally {
@@ -3051,8 +3074,8 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
-            return ImsManager.getInstance(mPhone.getContext(), getSlotIndexOrException(subId))
-                    .getConfigInterface().setConfig(key, value);
+            return ImsManager.getInstance(mApp,
+                    getSlotIndexOrException(subId)).getConfigInterface().setConfig(key, value);
         } catch (ImsException e) {
             throw new IllegalArgumentException(e.getMessage());
         } finally {
@@ -3206,10 +3229,6 @@
         }
     }
 
-    public void setPhone(Phone phone) {
-        mPhone = phone;
-    }
-
     /**
      * {@hide}
      * Returns Default subId, 0 in the case of single standby.
@@ -3236,7 +3255,7 @@
     public int getWhenToMakeWifiCalls() {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return Settings.System.getInt(mPhone.getContext().getContentResolver(),
+            return Settings.System.getInt(mApp.getContentResolver(),
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS,
                     getWhenToMakeWifiCallsDefaultPreference());
         } finally {
@@ -3251,7 +3270,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
-            Settings.System.putInt(mPhone.getContext().getContentResolver(),
+            Settings.System.putInt(mApp.getContentResolver(),
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -3274,8 +3293,8 @@
         try {
             if (TextUtils.equals(ISDR_AID, aid)) {
                 // Only allows LPA to open logical channel to ISD-R.
-                ComponentInfo bestComponent =
-                        EuiccConnector.findBestComponent(mPhone.getContext().getPackageManager());
+                ComponentInfo bestComponent = EuiccConnector.findBestComponent(getDefaultPhone()
+                        .getContext().getPackageManager());
                 if (bestComponent == null
                         || !TextUtils.equals(callingPackage, bestComponent.packageName)) {
                     loge("The calling package is not allowed to access ISD-R.");
@@ -3361,8 +3380,8 @@
             if (command == SELECT_COMMAND && p1 == SELECT_P1 && p2 == SELECT_P2 && p3 == SELECT_P3
                     && TextUtils.equals(ISDR_AID, data)) {
                 // Only allows LPA to select ISD-R.
-                ComponentInfo bestComponent =
-                        EuiccConnector.findBestComponent(mPhone.getContext().getPackageManager());
+                ComponentInfo bestComponent = EuiccConnector.findBestComponent(getDefaultPhone()
+                        .getContext().getPackageManager());
                 if (bestComponent == null
                         || !TextUtils.equals(callingPackage, bestComponent.packageName)) {
                     loge("The calling package is not allowed to select ISD-R.");
@@ -3611,14 +3630,15 @@
     }
 
     public String[] getPcscfAddress(String apnType, String callingPackage) {
+        final Phone defaultPhone = getDefaultPhone();
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, mPhone.getSubId(), callingPackage, "getPcscfAddress")) {
+                mApp, defaultPhone.getSubId(), callingPackage, "getPcscfAddress")) {
             return new String[0];
         }
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            return mPhone.getPcscfAddress(apnType);
+            return defaultPhone.getPcscfAddress(apnType);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3772,7 +3792,7 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            mPhone.setImsRegistrationState(registered);
+            getDefaultPhone().setImsRegistrationState(registered);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3904,15 +3924,16 @@
      */
     @Override
     public int getCalculatedPreferredNetworkType(String callingPackage) {
-        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, mPhone.getSubId(), callingPackage, "getCalculatedPreferredNetworkType")) {
+        final Phone defaultPhone = getDefaultPhone();
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
+                callingPackage, "getCalculatedPreferredNetworkType")) {
             return RILConstants.PREFERRED_NETWORK_MODE;
         }
 
         final long identity = Binder.clearCallingIdentity();
         try {
             // FIXME: need to get SubId from somewhere.
-            return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext(), 0);
+            return PhoneFactory.calculatePreferredNetworkType(defaultPhone.getContext(), 0);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3960,7 +3981,7 @@
                     CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
             if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
             if (success) {
-                Settings.Global.putInt(mPhone.getContext().getContentResolver(),
+                Settings.Global.putInt(mApp.getContentResolver(),
                         Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
             }
             return success;
@@ -3982,11 +4003,12 @@
         enforceModifyPermission();
 
         final long identity = Binder.clearCallingIdentity();
+        final Phone defaultPhone = getDefaultPhone();
         try {
-            int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
+            int dunRequired = Settings.Global.getInt(defaultPhone.getContext().getContentResolver(),
                     Settings.Global.TETHER_DUN_REQUIRED, 2);
             // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting
-            if (dunRequired == 2 && mPhone.hasMatchedTetherApnSetting()) {
+            if (dunRequired == 2 && defaultPhone.hasMatchedTetherApnSetting()) {
                 dunRequired = 1;
             }
             return dunRequired;
@@ -4015,7 +4037,7 @@
                 if (DBG) log("setUserDataEnabled: subId=" + subId + " enable=" + enable);
                 phone.setUserDataEnabled(enable);
             } else {
-                loge("setUserDataEnabled: no phone for subId=" + subId);
+                loge("setUserDataEnabled: no phone found. Invalid subId=" + subId);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4147,14 +4169,16 @@
 
     @Override
     public int checkCarrierPrivilegesForPackage(String pkgName) {
+        final Phone defaultPhone = getDefaultPhone();
         if (TextUtils.isEmpty(pkgName))
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
-        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
+        UiccCard card = UiccController.getInstance().getUiccCard(defaultPhone.getPhoneId());
         if (card == null) {
             loge("checkCarrierPrivilegesForPackage: No UICC");
             return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
         }
-        return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgName);
+        return card.getCarrierPrivilegeStatus(defaultPhone.getContext().getPackageManager(),
+                pkgName);
     }
 
     @Override
@@ -4169,8 +4193,7 @@
               continue;
             }
 
-            result = card.getCarrierPrivilegeStatus(
-                mPhone.getContext().getPackageManager(), pkgName);
+            result = card.getCarrierPrivilegeStatus(mApp.getPackageManager(), pkgName);
             if (result == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                 break;
             }
@@ -4190,13 +4213,12 @@
             loge("getCarrierPackageNamesForIntent: No UICC");
             return null ;
         }
-        return card.getCarrierPackageNamesForIntent(
-                mPhone.getContext().getPackageManager(), intent);
+        return card.getCarrierPackageNamesForIntent(mApp.getPackageManager(), intent);
     }
 
     @Override
     public List<String> getPackagesWithCarrierPrivileges() {
-        PackageManager pm = mPhone.getContext().getPackageManager();
+        PackageManager pm = mApp.getPackageManager();
         List<String> privilegedPackages = new ArrayList<>();
         List<PackageInfo> packages = null;
         for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
@@ -4352,7 +4374,7 @@
 
         final long identity  = Binder.clearCallingIdentity();
         try {
-            final Context context = mPhone.getContext();
+            final Context context = mApp;
             final TelephonyManager tele = TelephonyManager.from(context);
             final SubscriptionManager sub = SubscriptionManager.from(context);
 
@@ -4518,11 +4540,13 @@
 
     @Override
     public void enableVideoCalling(boolean enable) {
+        final Phone defaultPhone = getDefaultPhone();
         enforceModifyPermission();
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()).setVtSetting(enable);
+            ImsManager.getInstance(defaultPhone.getContext(),
+                    defaultPhone.getPhoneId()).setVtSetting(enable);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4530,8 +4554,9 @@
 
     @Override
     public boolean isVideoCallingEnabled(String callingPackage) {
+        final Phone defaultPhone = getDefaultPhone();
         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
-                mApp, mPhone.getSubId(), callingPackage, "isVideoCallingEnabled")) {
+                mApp, defaultPhone.getSubId(), callingPackage, "isVideoCallingEnabled")) {
             return false;
         }
 
@@ -4542,7 +4567,7 @@
             // In the long run, we may instead need to check if there exists a connection service
             // which can support video calling.
             ImsManager imsManager =
-                    ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
+                    ImsManager.getInstance(defaultPhone.getContext(), defaultPhone.getPhoneId());
             return imsManager.isVtEnabledByPlatform()
                     && imsManager.isEnhanced4gLteModeSettingEnabledByUser()
                     && imsManager.isVtEnabledByUser();
@@ -4562,7 +4587,7 @@
         try {
             CarrierConfigManager configManager =
                     (CarrierConfigManager) mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-            return configManager.getConfigForSubId(mPhone.getSubId())
+            return configManager.getConfigForSubId(subId)
                     .getBoolean(CarrierConfigManager.KEY_DTMF_TYPE_ENABLED_BOOL);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4580,7 +4605,7 @@
         try {
             CarrierConfigManager configManager =
                     (CarrierConfigManager) mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-            return configManager.getConfigForSubId(mPhone.getSubId())
+            return configManager.getConfigForSubId(subId)
                     .getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4589,7 +4614,7 @@
 
     @Override
     public boolean isTtyModeSupported() {
-        TelecomManager telecomManager = TelecomManager.from(mPhone.getContext());
+        TelecomManager telecomManager = TelecomManager.from(mApp);
         return telecomManager.isTtySupported();
     }
 
@@ -4597,7 +4622,7 @@
     public boolean isHearingAidCompatibilitySupported() {
         final long identity = Binder.clearCallingIdentity();
         try {
-            return mPhone.getContext().getResources().getBoolean(R.bool.hac_enabled);
+            return mApp.getResources().getBoolean(R.bool.hac_enabled);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4612,12 +4637,16 @@
     @Override
     public boolean isRttSupported(int subscriptionId) {
         final long identity = Binder.clearCallingIdentity();
+        final Phone phone = getPhone(subscriptionId);
+        if (phone == null) {
+            loge("isRttSupported: no Phone found. Invalid subId:" + subscriptionId);
+            return false;
+        }
         try {
-            boolean isCarrierSupported = mApp.getCarrierConfigForSubId(
-                    mPhone.getSubId()).getBoolean(
+            boolean isCarrierSupported = mApp.getCarrierConfigForSubId(subscriptionId).getBoolean(
                     CarrierConfigManager.KEY_RTT_SUPPORTED_BOOL);
             boolean isDeviceSupported =
-                    mPhone.getContext().getResources().getBoolean(R.bool.config_support_rtt);
+                    phone.getContext().getResources().getBoolean(R.bool.config_support_rtt);
             return isCarrierSupported && isDeviceSupported;
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4632,8 +4661,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             return isRttSupported(subscriptionId) && Settings.Secure.getInt(
-                    mPhone.getContext().getContentResolver(),
-                    Settings.Secure.RTT_CALLING_MODE, 0) != 0;
+                    mApp.getContentResolver(), Settings.Secure.RTT_CALLING_MODE, 0) != 0;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -4751,14 +4779,15 @@
         }
 
         final long identity = Binder.clearCallingIdentity();
+
         try {
             if (SubscriptionManager.isUsableSubIdValue(subId) && !mUserManager.hasUserRestriction(
                     UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
                 setUserDataEnabled(subId, getDefaultDataEnabled());
                 setNetworkSelectionModeAutomatic(subId);
                 setPreferredNetworkType(subId, getDefaultNetworkType(subId));
-                mPhone.setDataRoamingEnabled(getDefaultDataRoamingEnabled(subId));
-                CarrierInfoManager.deleteAllCarrierKeysForImsiEncryption(mPhone.getContext());
+                setDataRoamingEnabled(subId, getDefaultDataRoamingEnabled(subId));
+                CarrierInfoManager.deleteAllCarrierKeysForImsiEncryption(mApp);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -4818,8 +4847,7 @@
             // exact locale (e.g. fr_FR = French/France). So, if the locale returned from
             // the SIM and carrier preferences does not include a country we add the country
             // determined from the SIM MCC to provide an exact locale.
-            final Locale mccLocale = MccTable.getLocaleFromMcc(mPhone.getContext(), mcc,
-                    simLanguage);
+            final Locale mccLocale = MccTable.getLocaleFromMcc(mApp, mcc, simLanguage);
             if (mccLocale != null) {
                 if (DBG) log("No locale from default SIM, using mcc locale:" + mccLocale);
                 return mccLocale.toLanguageTag();
@@ -4833,16 +4861,14 @@
     }
 
     private List<SubscriptionInfo> getAllSubscriptionInfoList() {
-        return mSubscriptionController.getAllSubInfoList(
-                mPhone.getContext().getOpPackageName());
+        return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName());
     }
 
     /**
      * NOTE: this method assumes permission checks are done and caller identity has been cleared.
      */
     private List<SubscriptionInfo> getActiveSubscriptionInfoListPrivileged() {
-        return mSubscriptionController.getActiveSubscriptionInfoList(
-                mPhone.getContext().getOpPackageName());
+        return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName());
     }
 
     private final ModemActivityInfo mLastModemActivityInfo =
@@ -4957,7 +4983,7 @@
         try {
             Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(accountHandle);
             if (phone == null) {
-                phone = mPhone;
+                phone = getDefaultPhone();
             }
 
             return VoicemailNotificationSettingsUtil.getRingtoneUri(phone.getContext());
@@ -4980,9 +5006,10 @@
     @Override
     public void setVoicemailRingtoneUri(String callingPackage,
             PhoneAccountHandle phoneAccountHandle, Uri uri) {
+        final Phone defaultPhone = getDefaultPhone();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         if (!TextUtils.equals(callingPackage,
-                TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage())) {
+                TelecomManager.from(defaultPhone.getContext()).getDefaultDialerPackage())) {
             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                     mApp, PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle),
                     "setVoicemailRingtoneUri");
@@ -4992,7 +5019,7 @@
         try {
             Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(phoneAccountHandle);
             if (phone == null) {
-                phone = mPhone;
+                phone = defaultPhone;
             }
             VoicemailNotificationSettingsUtil.setRingtoneUri(phone.getContext(), uri);
         } finally {
@@ -5013,7 +5040,7 @@
         try {
             Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(accountHandle);
             if (phone == null) {
-                phone = mPhone;
+                phone = getDefaultPhone();
             }
 
             return VoicemailNotificationSettingsUtil.isVibrationEnabled(phone.getContext());
@@ -5036,9 +5063,10 @@
     @Override
     public void setVoicemailVibrationEnabled(String callingPackage,
             PhoneAccountHandle phoneAccountHandle, boolean enabled) {
+        final Phone defaultPhone = getDefaultPhone();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         if (!TextUtils.equals(callingPackage,
-                TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage())) {
+                TelecomManager.from(defaultPhone.getContext()).getDefaultDialerPackage())) {
             TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
                     mApp, PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle),
                     "setVoicemailVibrationEnabled");
@@ -5048,7 +5076,7 @@
         try {
             Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(phoneAccountHandle);
             if (phone == null) {
-                phone = mPhone;
+                phone = defaultPhone;
             }
             VoicemailNotificationSettingsUtil.setVibrationEnabled(phone.getContext(), enabled);
         } finally {
@@ -5085,7 +5113,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             ComponentName componentName =
-                    RemoteVvmTaskManager.getRemotePackage(mPhone.getContext(), subId);
+                    RemoteVvmTaskManager.getRemotePackage(mApp, subId);
             if (componentName == null) {
                 throw new SecurityException(
                         "Caller not current active visual voicemail package[null]");
@@ -5338,7 +5366,7 @@
      */
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (mPhone.getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+        if (mApp.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             writer.println("Permission Denial: can't dump Phone from pid="
                     + Binder.getCallingPid()
@@ -5347,7 +5375,7 @@
                     + android.Manifest.permission.DUMP);
             return;
         }
-        DumpsysHandler.dump(mPhone.getContext(), fd, writer, args);
+        DumpsysHandler.dump(mApp, fd, writer, args);
     }
 
     @Override
@@ -5431,7 +5459,7 @@
     }
 
     private WorkSource getWorkSource(int uid) {
-        String packageName = mPhone.getContext().getPackageManager().getNameForUid(uid);
+        String packageName = mApp.getPackageManager().getNameForUid(uid);
         return new WorkSource(uid, packageName);
     }
 
@@ -5464,8 +5492,7 @@
 
     private boolean isUssdApiAllowed(int subId) {
         CarrierConfigManager configManager =
-                (CarrierConfigManager) mPhone.getContext().getSystemService(
-                        Context.CARRIER_CONFIG_SERVICE);
+                (CarrierConfigManager) mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager == null) {
             return false;
         }
@@ -5693,6 +5720,21 @@
     }
 
     @Override
+    public int getCardIdForDefaultEuicc(int subId, String callingPackage) {
+        if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
+                mApp, subId, callingPackage, "getCardIdForDefaultEuicc")) {
+            return TelephonyManager.INVALID_CARD_ID;
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return UiccController.getInstance().getCardIdForDefaultEuicc();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     public void setRadioIndicationUpdateMode(int subId, int filters, int mode) {
         enforceModifyPermission();
         final Phone phone = getPhone(subId);
@@ -5755,7 +5797,7 @@
      */
     private boolean getDefaultDataRoamingEnabled(int subId) {
         final CarrierConfigManager configMgr = (CarrierConfigManager)
-                mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+                mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         boolean isDataRoamingEnabled = "true".equalsIgnoreCase(
                 SystemProperties.get(DEFAULT_DATA_ROAMING_PROPERTY_NAME, "false"));
         isDataRoamingEnabled |= configMgr.getConfigForSubId(subId).getBoolean(
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 1a25ae3..9250118 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -16,6 +16,8 @@
 
 package com.android.phone;
 
+import android.os.Binder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -41,6 +43,8 @@
 
     private static final String IMS_SUBCOMMAND = "ims";
     private static final String SMS_SUBCOMMAND = "sms";
+    private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
+
     private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
     private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
     private static final String IMS_ENABLE = "enable";
@@ -50,6 +54,9 @@
     private static final String SMS_GET_DEFAULT_APP = "get-default-app";
     private static final String SMS_SET_DEFAULT_APP = "set-default-app";
 
+    private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
+    private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
+
     // Take advantage of existing methods that already contain permissions checks when possible.
     private final ITelephony mInterface;
 
@@ -70,6 +77,8 @@
             case SMS_SUBCOMMAND: {
                 return handleSmsCommand();
             }
+            case NUMBER_VERIFICATION_SUBCOMMAND:
+                return handleNumberVerificationCommand();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -126,6 +135,18 @@
         pw.println("    Set PACKAGE_NAME as the default SMS app.");
     }
 
+
+    private void onHelpNumberVerification() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Number verification commands");
+        pw.println("  numverify override-package PACKAGE_NAME;");
+        pw.println("    Set the authorized package for number verification.");
+        pw.println("    Leave the package name blank to reset.");
+        pw.println("  numverify fake-call NUMBER;");
+        pw.println("    Fake an incoming call from NUMBER. This is for testing. Output will be");
+        pw.println("    1 if the call would have been intercepted, 0 otherwise.");
+    }
+
     private int handleImsCommand() {
         String arg = getNextArg();
         if (arg == null) {
@@ -151,6 +172,33 @@
         return -1;
     }
 
+    private int handleNumberVerificationCommand() {
+        String arg = getNextArg();
+        if (arg == null) {
+            onHelpNumberVerification();
+            return 0;
+        }
+
+        if (!checkShellUid()) {
+            return -1;
+        }
+
+        switch (arg) {
+            case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
+                NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
+                return 0;
+            }
+            case NUMBER_VERIFICATION_FAKE_CALL: {
+                boolean val = NumberVerificationManager.getInstance()
+                        .checkIncomingCall(getNextArg());
+                getOutPrintWriter().println(val ? "1" : "0");
+                return 0;
+            }
+        }
+
+        return -1;
+    }
+
     // ims set-ims-service
     private int handleImsSetServiceCommand() {
         PrintWriter errPw = getErrPrintWriter();
@@ -400,4 +448,10 @@
         getOutPrintWriter().println("SMS app set to " + mInterface.getDefaultSmsApp(userId));
         return 0;
     }
+
+    private boolean checkShellUid() {
+        // adb can run as root or as shell, depending on whether the device is rooted.
+        return Binder.getCallingUid() == Process.SHELL_UID
+                || Binder.getCallingUid() == Process.ROOT_UID;
+    }
 }
diff --git a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
index 0cd3108..7d9b4f0 100644
--- a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
+++ b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
@@ -25,6 +25,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import java.io.BufferedInputStream;
 import java.io.IOException;
@@ -109,6 +110,11 @@
         }
     }
 
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    Map<String, CountryEccInfo> getEccTable() {
+        return mEccTable;
+    }
+
     private ProtobufEccData.AllInfo parseEccData(InputStream input) throws IOException {
         return ProtobufEccData.AllInfo.parseFrom(new GZIPInputStream(input));
     }
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index 4dfaf44..223616f 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -37,6 +37,7 @@
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsExternalConnection;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
+import com.android.phone.NumberVerificationManager;
 import com.android.phone.PhoneUtils;
 
 import com.google.common.base.Preconditions;
@@ -126,6 +127,19 @@
         Connection connection = (Connection) asyncResult.result;
         if (connection != null) {
             Call call = connection.getCall();
+            // Check if we have a pending number verification request.
+            if (connection.getAddress() != null) {
+                if (NumberVerificationManager.getInstance()
+                        .checkIncomingCall(connection.getAddress())) {
+                    // Disconnect the call if it matches
+                    try {
+                        connection.hangup();
+                    } catch (CallStateException e) {
+                        Log.e(this, e, "Error hanging up potential number verification call");
+                    }
+                    return;
+                }
+            }
 
             // Final verification of the ringing state before sending the intent to Telecom.
             if (call != null && call.getState().isRinging()) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index f986994..8ae7b8a 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -433,7 +433,7 @@
                         // been powered on and isn't in the UNAVAILABLE state, even if it is
                         // reporting the OUT_OF_SERVICE state.
                         return (phone.getState() == PhoneConstants.State.OFFHOOK)
-                            || phone.getServiceStateTracker().isRadioOn();
+                            || phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
                     } else {
                         // It is not an emergency number, so wait until we are in service and ready
                         // to make calls. This can happen when we power down the radio on bluetooth
diff --git a/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml b/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml
index 668b708..5145a63 100644
--- a/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml
+++ b/testapps/TelephonyManagerTestApp/res/layout/calling_method.xml
@@ -58,11 +58,12 @@
         android:ellipsize="marquee"
         android:textSize="30sp" />
 
-    <ListView
-        android:id="@android:id/list"
+    <LinearLayout
+        android:id="@+id/method_params"
+        android:orientation="vertical"
         android:layout_height="wrap_content"
         android:layout_width="fill_parent">
-    </ListView>
+    </LinearLayout>
 
     <Button
         android:id="@+id/go_button"
@@ -72,10 +73,18 @@
         android:layout_height="50dip">
     </Button>
 
-    <TextView
-        android:id="@+id/return_value"
+
+    <ScrollView
+        android:id="@+id/return_value_wrapper"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:ellipsize="marquee"
-        android:textSize="15sp" />
+        android:scrollbars="vertical"
+        android:fillViewport="true">
+        <TextView
+            android:id="@+id/return_value"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:ellipsize="marquee"
+            android:textSize="15sp" />
+    </ScrollView>
 </LinearLayout>
diff --git a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/CallingMethodActivity.java b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/CallingMethodActivity.java
index aa9dbc0..4bf8220 100644
--- a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/CallingMethodActivity.java
+++ b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/CallingMethodActivity.java
@@ -16,27 +16,28 @@
 
 package com.android.phone.testapps.telephonymanagertestapp;
 
-import android.app.ListActivity;
+import android.app.Activity;
 import android.os.Bundle;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
 
 /**
  * Activity to call a specific method of TelephonyManager.
  */
-public class CallingMethodActivity extends ListActivity {
+public class CallingMethodActivity extends Activity {
     private Class[] mParameterTypes;
     private Object[] mParameterValues;
+    EditText[] mEditTexts;
     private Button mGoButton;
     private Method mMethod;
     private TextView mReturnValue;
@@ -57,10 +58,11 @@
         mGoButton = findViewById(R.id.go_button);
         mReturnValue = findViewById(R.id.return_value);
         mSubIdField = findViewById(R.id.sub_id_value);
-        setListAdapter(new ParameterListAdapter());
 
         mParameterTypes = mMethod.getParameterTypes();
         mParameterValues = new Object[mParameterTypes.length];
+        mEditTexts = new EditText[mParameterTypes.length];
+        populateParamList();
 
         String tags = Modifier.toString(mMethod.getModifiers()) + ' '
                 + TelephonyManagerTestApp.getShortTypeName(mMethod.getReturnType().toString());
@@ -76,13 +78,18 @@
             int subId = Integer.parseInt(mSubIdField.getText().toString());
 
             for (int i = 0; i < mParameterTypes.length; i++) {
-                String text = ((EditText) getListAdapter().getItem(i)).getText().toString();
+                String text = mEditTexts[i].getText().toString();
                 if (mParameterTypes[i] == int.class) {
                     mParameterValues[i] = Integer.parseInt(text);
                 } else if (mParameterTypes[i] == boolean.class) {
                     mParameterValues[i] = Boolean.parseBoolean(text);
-                } else if (mParameterTypes[i] == Long.class) {
+                } else if (mParameterTypes[i] == long.class) {
                     mParameterValues[i] = Long.parseLong(text);
+                } else if (mParameterTypes[i] == String.class) {
+                    mParameterValues[i] = text;
+                } else {
+                    mParameterValues[i] =
+                            ParameterParser.get(this).executeParser(mParameterTypes[i], text);
                 }
             }
             Log.d(TelephonyManagerTestApp.TAG, "Invoking method " + mMethod.getName());
@@ -103,50 +110,22 @@
             }
 
         } catch (Exception exception) {
-            Log.d(TelephonyManagerTestApp.TAG, "NoSuchMethodException " + exception);
-            mReturnValue.setText("NoSuchMethodException " + exception);
+            Log.d(TelephonyManagerTestApp.TAG, "Exception: " + exception);
+            StringWriter s = new StringWriter();
+            PrintWriter stack = new PrintWriter(s);
+            exception.printStackTrace(stack);
+            mReturnValue.setText("Exception " + exception.getMessage() + "\n" + s.toString());
         }
     }
 
-    private class ParameterListAdapter extends BaseAdapter {
-        ArrayList<EditText> mEditTexts = new ArrayList<>();
-        @Override
-        public int getCount() {
-            return mParameterTypes == null ? 0 : mParameterTypes.length;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup container) {
-            if (mParameterTypes == null || mParameterTypes.length <= position) {
-                return null;
-            }
-
-            if (convertView == null) {
-                convertView = getLayoutInflater().inflate(
-                        R.layout.parameter_field, container, false);
-            }
-
-            Class aClass = mParameterTypes[position];
-
-            ((TextView) convertView.findViewById(R.id.field_name)).setText(
+    private void populateParamList() {
+        for (int i = 0; i < mParameterTypes.length; i++) {
+            View view = getLayoutInflater().inflate(R.layout.parameter_field, null);
+            Class aClass = mParameterTypes[i];
+            ((TextView) view.findViewById(R.id.field_name)).setText(
                     TelephonyManagerTestApp.getShortTypeName(aClass.toString()) + ": ");
-            mEditTexts.add(convertView.findViewById(R.id.field_value));
-
-            return convertView;
-        }
-
-        @Override
-        public Object getItem(int position) {
-            if (mEditTexts == null || mEditTexts.size() <= position) {
-                return null;
-            }
-
-            return mEditTexts.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
+            mEditTexts[i] = view.findViewById(R.id.field_value);
+            ((LinearLayout) findViewById(R.id.method_params)).addView(view);
         }
     }
 }
diff --git a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
new file mode 100644
index 0000000..097c90a
--- /dev/null
+++ b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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.phone.testapps.telephonymanagertestapp;
+
+import android.content.Context;
+import android.telephony.NumberVerificationCallback;
+import android.telephony.PhoneNumberRange;
+import android.widget.Toast;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Function;
+
+class ParameterParser {
+    private static ParameterParser sInstance;
+
+    static ParameterParser get(Context context) {
+        if (sInstance == null) {
+            sInstance = new ParameterParser(context);
+        }
+        return sInstance;
+    }
+
+    private final Context mContext;
+    private final Map<Class, Function<String, Object>> mParsers =
+            new HashMap<Class, Function<String, Object>>() {{
+                put(PhoneNumberRange.class, ParameterParser::parsePhoneNumberRange);
+                put(Executor.class, s -> parseExecutor(s));
+                put(NumberVerificationCallback.class, s -> parseNumberVerificationCallback(s));
+            }};
+
+    private ParameterParser(Context context) {
+        mContext = context;
+    }
+
+    Object executeParser(Class type, String input) {
+        return mParsers.getOrDefault(type, s -> null).apply(input);
+    }
+
+    private static PhoneNumberRange parsePhoneNumberRange(String input) {
+        String[] parts = input.split(" ");
+        if (parts.length != 4) {
+            return null;
+        }
+        return new PhoneNumberRange(parts[0], parts[1], parts[2], parts[3]);
+    }
+
+    private Executor parseExecutor(String input) {
+        return mContext.getMainExecutor();
+    }
+
+    private NumberVerificationCallback parseNumberVerificationCallback(String input) {
+        return new NumberVerificationCallback() {
+            @Override
+            public void onCallReceived(String phoneNumber) {
+                Toast.makeText(mContext, "Received verification " + phoneNumber,
+                        Toast.LENGTH_SHORT).show();
+            }
+
+            @Override
+            public void onVerificationFailed(int reason) {
+                Toast.makeText(mContext, "Verification failed " + reason,
+                        Toast.LENGTH_SHORT).show();
+            }
+        };
+    }
+}
diff --git a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/TelephonyManagerTestApp.java b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/TelephonyManagerTestApp.java
index 45c76a7..760c3bd 100644
--- a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/TelephonyManagerTestApp.java
+++ b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/TelephonyManagerTestApp.java
@@ -158,7 +158,7 @@
             mFilteredMethods.addAll(mMethods);
         } else {
             for (Method method : mMethods) {
-                if (method.getName().contains(text)) {
+                if (method.getName().toLowerCase().contains(text.toLowerCase())) {
                     mFilteredMethods.add(method);
                 }
             }
diff --git a/tests/src/com/android/phone/NumberVerificationManagerTest.java b/tests/src/com/android/phone/NumberVerificationManagerTest.java
new file mode 100644
index 0000000..d476ba5
--- /dev/null
+++ b/tests/src/com/android/phone/NumberVerificationManagerTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 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.phone;
+
+import static junit.framework.TestCase.assertFalse;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.telephony.NumberVerificationCallback;
+import android.telephony.PhoneNumberRange;
+import android.telephony.ServiceState;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.INumberVerificationCallback;
+import com.android.internal.telephony.Phone;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class NumberVerificationManagerTest {
+    private static final PhoneNumberRange SAMPLE_RANGE =
+            new PhoneNumberRange("1", "650555", "0000", "8999");
+    private static final long DEFAULT_VERIFICATION_TIMEOUT = 100;
+    @Mock private Phone mPhone1;
+    @Mock private Phone mPhone2;
+    @Mock private Call mRingingCall;
+    @Mock private Call mForegroundCall;
+    @Mock private Call mBackgroundCall;
+    @Mock private INumberVerificationCallback mCallback;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ServiceState ss = mock(ServiceState.class);
+        when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        when(mPhone1.getServiceState()).thenReturn(ss);
+        when(mPhone1.getForegroundCall()).thenReturn(mForegroundCall);
+        when(mPhone1.getRingingCall()).thenReturn(mRingingCall);
+        when(mPhone1.getBackgroundCall()).thenReturn(mBackgroundCall);
+        when(mPhone2.getServiceState()).thenReturn(ss);
+        when(mPhone2.getForegroundCall()).thenReturn(mForegroundCall);
+        when(mPhone2.getRingingCall()).thenReturn(mRingingCall);
+        when(mPhone2.getBackgroundCall()).thenReturn(mBackgroundCall);
+
+        when(mForegroundCall.getState()).thenReturn(Call.State.IDLE);
+        when(mRingingCall.getState()).thenReturn(Call.State.IDLE);
+        when(mBackgroundCall.getState()).thenReturn(Call.State.IDLE);
+    }
+
+    @Test
+    public void testConcurrentRequestFailure() throws Exception {
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1});
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, times(1)).onVerificationFailed(
+                NumberVerificationCallback.REASON_CONCURRENT_REQUESTS);
+    }
+
+    @Test
+    public void testEcbmFailure() throws Exception {
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1});
+        when(mPhone1.isInEcm()).thenReturn(true);
+
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, times(1)).onVerificationFailed(
+                NumberVerificationCallback.REASON_IN_ECBM);
+    }
+
+    @Test
+    public void testEmergencyCallFailure() throws Exception {
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1});
+        when(mPhone1.isInEmergencyCall()).thenReturn(true);
+
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, times(1)).onVerificationFailed(
+                NumberVerificationCallback.REASON_IN_EMERGENCY_CALL);
+    }
+
+    @Test
+    public void testNoPhoneInServiceFailure() throws Exception {
+        ServiceState ss = mock(ServiceState.class);
+        when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
+        when(mPhone1.getServiceState()).thenReturn(ss);
+        when(mPhone2.getServiceState()).thenReturn(ss);
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
+
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, times(1)).onVerificationFailed(
+                NumberVerificationCallback.REASON_NETWORK_NOT_AVAILABLE);
+    }
+
+    @Test
+    public void testAllLinesFullFailure() throws Exception {
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
+        when(mRingingCall.getState()).thenReturn(Call.State.ALERTING);
+
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, times(1)).onVerificationFailed(
+                NumberVerificationCallback.REASON_TOO_MANY_CALLS);
+    }
+
+    private void verifyDefaultRangeMatching(NumberVerificationManager manager) throws Exception {
+        String testNumber = "6505550000";
+        assertTrue(manager.checkIncomingCall(testNumber));
+        verify(mCallback).onCallReceived(testNumber);
+    }
+
+    @Test
+    public void testVerificationWorksWithOnePhoneInService() throws Exception {
+        ServiceState ss = mock(ServiceState.class);
+        when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
+        when(mPhone1.getServiceState()).thenReturn(ss);
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
+
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, never()).onVerificationFailed(anyInt());
+        verifyDefaultRangeMatching(manager);
+    }
+
+    @Test
+    public void testVerificationWorksWithOnePhoneFull() throws Exception {
+        Call fakeCall = mock(Call.class);
+        when(fakeCall.getState()).thenReturn(Call.State.ACTIVE);
+        when(mPhone1.getForegroundCall()).thenReturn(fakeCall);
+        when(mPhone1.getRingingCall()).thenReturn(fakeCall);
+        when(mPhone1.getBackgroundCall()).thenReturn(fakeCall);
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
+
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verify(mCallback, never()).onVerificationFailed(anyInt());
+        verifyDefaultRangeMatching(manager);
+    }
+
+    @Test
+    public void testDoubleVerificationFailure() throws Exception {
+        NumberVerificationManager manager =
+                new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
+        manager.requestVerification(SAMPLE_RANGE, mCallback, DEFAULT_VERIFICATION_TIMEOUT);
+        verifyDefaultRangeMatching(manager);
+        assertFalse(manager.checkIncomingCall("this doesn't even matter"));
+    }
+}
diff --git a/tests/src/com/android/phone/ecc/IsoToEccProtobufRepositoryTest.java b/tests/src/com/android/phone/ecc/IsoToEccProtobufRepositoryTest.java
new file mode 100644
index 0000000..f6e5ba2
--- /dev/null
+++ b/tests/src/com/android/phone/ecc/IsoToEccProtobufRepositoryTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 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.phone.ecc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.android.TelephonyTestBase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Unit tests for IsoToEccProtobufRepository.
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class IsoToEccProtobufRepositoryTest extends TelephonyTestBase {
+    private static final String LOG_TAG = "IsoToEccProtobufRepositoryTest";
+
+    @Test
+    public void testEccDataContent() {
+        IsoToEccProtobufRepository repository = IsoToEccProtobufRepository.getInstance();
+        repository.loadMappingTable(InstrumentationRegistry.getTargetContext());
+        Map<String, CountryEccInfo> eccTable = repository.getEccTable();
+        HashSet loadedIsos = new HashSet(300);
+        HashSet loadedNumbers = new HashSet(5);
+
+        assertThat(eccTable).isNotEmpty();
+        for (Map.Entry<String, CountryEccInfo> entry : eccTable.entrySet()) {
+            String countryIso = entry.getKey();
+            CountryEccInfo countryEccInfo = entry.getValue();
+            EccInfo[] eccInfoList = countryEccInfo.getEccInfoList();
+            if (eccInfoList.length > 0) {
+                Log.i(LOG_TAG, "Verifying country " + countryIso + " with "
+                        + eccInfoList.length + " ecc(s)");
+            } else {
+                Log.w(LOG_TAG, "Verifying country " + countryIso + " with no ecc");
+            }
+
+            assertThat(countryIso).isNotEmpty();
+            assertThat(countryIso).isEqualTo(countryIso.toUpperCase().trim());
+            assertThat(loadedIsos.contains(countryIso)).isFalse();
+            loadedIsos.add(countryIso);
+
+            assertThat(countryEccInfo.getFallbackEcc()).isNotEmpty();
+
+            if (eccInfoList.length != 0) {
+                loadedNumbers.clear();
+                for (EccInfo eccInfo : eccInfoList) {
+                    String eccNumber = eccInfo.getNumber();
+                    assertThat(eccNumber).isNotEmpty();
+                    assertThat(eccNumber).isEqualTo(eccNumber.trim());
+                    assertThat(eccInfo.getTypes()).isNotEmpty();
+                    assertThat(loadedNumbers.contains(eccNumber)).isFalse();
+                    loadedNumbers.add(eccNumber);
+                }
+            }
+        }
+    }
+}