Merge "Conference's connections use participants' own connect time if available."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ce774d8..9f9269e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -22,10 +22,6 @@
         android:sharedUserLabel="@string/phoneAppLabel"
 >
 
-    <uses-sdk
-        android:minSdkVersion="23"
-        android:targetSdkVersion="26" />
-
     <original-package android:name="com.android.phone" />
 
     <protected-broadcast android:name="android.telecom.action.TTY_PREFERRED_MODE_CHANGED" />
@@ -92,6 +88,10 @@
     <protected-broadcast android:name= "android.telephony.action.SIM_SLOT_STATUS_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" />
     <protected-broadcast android:name= "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED" />
+    <protected-broadcast android:name= "android.telephony.action.NETWORK_COUNTRY_CHANGED" />
+
+    <!-- For Vendor Debugging in Telephony -->
+    <protected-broadcast android:name="android.telephony.debug.action.DEBUG_EVENT" />
 
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
diff --git a/res/layout/pref_dialog_editpin.xml b/res/layout/pref_dialog_editpin.xml
index a278690..94cdadf 100644
--- a/res/layout/pref_dialog_editpin.xml
+++ b/res/layout/pref_dialog_editpin.xml
@@ -22,7 +22,7 @@
     android:orientation="vertical"
     android:padding="?android:attr/dialogPreferredPadding">
 
-    <TextView android:id="@+android:id/message"
+    <TextView android:id="@android:id/message"
         style="?android:attr/textAppearanceSmall"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/res/values/config.xml b/res/values/config.xml
index b1f8ae8..6b6bf04 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -254,6 +254,7 @@
     <!-- Intent action to launch target emergency app. -->
     <string name="config_emergency_app_intent" translatable="false"></string>
 
-    <!-- Flag indicating whether shortcut view of promoted emergency numbers should be enabled. -->
-    <bool name="config_emergency_shortcut_view_enabled">false</bool>
+    <!-- The country list that shortcut view can be enabled. -->
+    <string-array name="config_countries_to_enable_shortcut_view" translatable="false">
+    </string-array>
 </resources>
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 80b4632..d7443d5 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -810,10 +810,6 @@
     }
 
     private boolean canEnableShortcutView(PersistableBundle carrierConfig) {
-        if (!getResources().getBoolean(R.bool.config_emergency_shortcut_view_enabled)) {
-            // Disables shortcut view by project.
-            return false;
-        }
         if (!carrierConfig.getBoolean(
                 CarrierConfigManager.KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL)) {
             Log.d(LOG_TAG, "Disables shortcut view by carrier requirement");
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 86babd5..465b89a 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -485,7 +485,7 @@
 
         public void onIntentUpdate(Intent intent) {
             if (!mUnavailable) {
-                updateCurrentTab(intent);
+                updateCurrentTab(intent.getExtras());
             }
         }
 
@@ -583,8 +583,7 @@
             }
         };
 
-        private int getSlotIdFromIntent(Intent intent) {
-            Bundle data = intent.getExtras();
+        private int getSlotIdFromBundle(Bundle data) {
             int subId = -1;
             if (data != null) {
                 subId = data.getInt(Settings.EXTRA_SUB_ID, -1);
@@ -754,8 +753,8 @@
                     mEmptyTabContent);
         }
 
-        private void updateCurrentTab(Intent intent) {
-            int slotId = getSlotIdFromIntent(intent);
+        private void updateCurrentTab(Bundle data) {
+            int slotId = getSlotIdFromBundle(data);
             if (slotId >= 0 && mTabHost != null && mTabHost.getCurrentTab() != slotId) {
                 mTabHost.setCurrentTab(slotId);
             }
@@ -768,6 +767,9 @@
             // If advanced fields are already expanded, we save it and expand it
             // when it's re-created.
             outState.putBoolean(EXPAND_ADVANCED_FIELDS, mExpandAdvancedFields);
+
+            // Save subId of currently shown tab.
+            outState.putInt(Settings.EXTRA_SUB_ID, mSubId);
         }
 
         @Override
@@ -851,7 +853,12 @@
                 getActivity().setContentView(R.layout.telephony_disallowed_preference_screen);
             } else {
                 initializeSubscriptions();
-                updateCurrentTab(getActivity().getIntent());
+
+                if (savedInstanceState != null) {
+                    updateCurrentTab(savedInstanceState);
+                } else {
+                    updateCurrentTab(getActivity().getIntent().getExtras());
+                }
             }
         }
 
diff --git a/src/com/android/phone/PhoneApp.java b/src/com/android/phone/PhoneApp.java
index 333e0ec..df151bf 100644
--- a/src/com/android/phone/PhoneApp.java
+++ b/src/com/android/phone/PhoneApp.java
@@ -19,7 +19,6 @@
 import android.app.Application;
 import android.os.UserHandle;
 
-import com.android.phone.ecc.IsoToEccProtobufRepository;
 import com.android.services.telephony.TelecomAccountRegistry;
 
 /**
@@ -41,10 +40,5 @@
 
             TelecomAccountRegistry.getInstance(this).setupOnBoot();
         }
-
-        new Thread(() -> {
-            // Preload ECC table in background.
-            IsoToEccProtobufRepository.getInstance().loadMappingTable(PhoneApp.this);
-        }).start();
     }
 }
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index ccbb4d0..a5cd06b 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -44,6 +44,7 @@
 import android.provider.Settings;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
+import android.telephony.DebugEventReporter;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -283,6 +284,9 @@
         //   getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS);
 
         if (mCM == null) {
+            // Initialize DebugEventReporter early so that it can be used
+            DebugEventReporter.initialize(this);
+
             // Inject telephony component factory if configured using other jars.
             XmlResourceParser parser = getResources().getXml(R.xml.telephony_injection);
             TelephonyComponentFactory.getInstance().injectTheComponentFactory(parser);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 5947024..e251516 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -265,6 +265,9 @@
     private static final String PREF_CARRIERS_SUBSCRIBER_PREFIX = "carrier_subscriber_";
     private static final String PREF_PROVISION_IMS_MMTEL_PREFIX = "provision_ims_mmtel_";
 
+    // String to store multi SIM allowed
+    private static final String PREF_MULTI_SIM_RESTRICTED = "multisim_restricted";
+
     // The AID of ISD-R.
     private static final String ISDR_AID = "A0000005591010FFFFFFFF8900000100";
 
@@ -2816,6 +2819,9 @@
         } catch (ImsException e) {
             Log.w(LOG_TAG, "IMS isCapable - service unavailable: " + e.getMessage());
             return false;
+        } catch (IllegalArgumentException e) {
+            Log.i(LOG_TAG, "isCapable: " + subId + " is inactive, returning false.");
+            return false;
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -3400,7 +3406,7 @@
     private int getSlotIndexOrException(int subId) throws IllegalArgumentException {
         int slotId = SubscriptionManager.getSlotIndex(subId);
         if (!SubscriptionManager.isValidSlotIndex(slotId)) {
-            throw new IllegalArgumentException("Invalid Subscription Id.");
+            throw new IllegalArgumentException("Invalid Subscription Id, subId=" + subId);
         }
         return slotId;
     }
@@ -4269,8 +4275,9 @@
      */
     @Override
     public int getPreferredNetworkType(int subId) {
-        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-                mApp, subId, "getPreferredNetworkType");
+        TelephonyPermissions
+                .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+                        mApp, subId, "getPreferredNetworkType");
 
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -6448,4 +6455,83 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    @Override
+    public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) {
+        enforceModifyPermission();
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mTelephonySharedPreferences.edit()
+                    .putBoolean(PREF_MULTI_SIM_RESTRICTED, isMultisimCarrierRestricted)
+                    .commit();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public boolean isMultisimCarrierRestricted() {
+        enforceReadPrivilegedPermission("isMultisimCarrierRestricted");
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            // If the device has less than 2 SIM cards, indicate that multisim is restricted.
+            int numPhysicalSlots = UiccController.getInstance().getUiccSlots().length;
+            if (numPhysicalSlots < 2) {
+                loge("isMultisimCarrierRestricted: requires at least 2 cards");
+                return true;
+            }
+
+            // Default value is false. Multi SIM is allowed unless explicitly restricted.
+            return mTelephonySharedPreferences.getBoolean(PREF_MULTI_SIM_RESTRICTED, false);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Switch configs to enable multi-sim or switch back to single-sim
+     * @param numOfSims number of active sims we want to switch to
+     */
+    @Override
+    public void switchMultiSimConfig(int numOfSims) {
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+                mApp, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, "switchMultiSimConfig");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mPhoneConfigurationManager.switchMultiSimConfig(numOfSims);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get how many sims have been activated on the phone
+     */
+    @Override
+    public int getNumOfActiveSims() {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mPhoneConfigurationManager.getNumOfActiveSims();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Get whether reboot is required or not after making changes to modem configurations.
+     * Return value defaults to false
+     */
+    @Override
+    public boolean isRebootRequiredForModemConfigChange() {
+        enforceReadPrivilegedPermission("isRebootRequiredForModemConfigChange");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mPhoneConfigurationManager.isRebootRequiredForModemConfigChange();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
 }
diff --git a/src/com/android/phone/ShortcutViewUtils.java b/src/com/android/phone/ShortcutViewUtils.java
index 28ee24f..595ea86 100644
--- a/src/com/android/phone/ShortcutViewUtils.java
+++ b/src/com/android/phone/ShortcutViewUtils.java
@@ -96,12 +96,12 @@
             return mPromotedEmergencyNumbers;
         }
 
-        public boolean isSufficientForEmergencyCall() {
+        public boolean isSufficientForEmergencyCall(@NonNull Context context) {
             // Checking mCountryIso because the emergency number list is not reliable to be
             // suggested to users if the device didn't camp to any network. In this case, users
             // can still try to dial emergency numbers with dial pad.
             return mCanPlaceEmergencyCall && mPromotedEmergencyNumbers != null
-                    && !TextUtils.isEmpty(mCountryIso);
+                    && isSupportedCountry(context, mCountryIso);
         }
 
         public boolean hasPromotedEmergencyNumber(String number) {
@@ -166,7 +166,7 @@
         if (defaultHandle != null) {
             PhoneInfo phone = loadPhoneInfo(defaultHandle, telephonyManager, telecomManager,
                     promotedLists);
-            if (phone.isSufficientForEmergencyCall()) {
+            if (phone.isSufficientForEmergencyCall(context)) {
                 return phone;
             }
             Log.w(LOG_TAG, "Default PhoneAccount is insufficient for emergency call: "
@@ -181,7 +181,7 @@
             for (PhoneAccountHandle handle : allHandles) {
                 PhoneInfo phone = loadPhoneInfo(handle, telephonyManager, telecomManager,
                         promotedLists);
-                if (phone.isSufficientForEmergencyCall()) {
+                if (phone.isSufficientForEmergencyCall(context)) {
                     return phone;
                 } else {
                     if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
@@ -196,6 +196,21 @@
         return null;
     }
 
+    private static boolean isSupportedCountry(@NonNull Context context, String countryIso) {
+        if (TextUtils.isEmpty(countryIso)) {
+            return false;
+        }
+
+        String[] countrysToEnableShortcutView = context.getResources().getStringArray(
+                R.array.config_countries_to_enable_shortcut_view);
+        for (String supportedCountry : countrysToEnableShortcutView) {
+            if (countryIso.equalsIgnoreCase(supportedCountry)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static PhoneInfo loadPhoneInfo(@NonNull PhoneAccountHandle handle,
             @NonNull TelephonyManager telephonyManager, @NonNull TelecomManager telecomManager,
             Map<Integer, List<EmergencyNumber>> promotedLists) {
diff --git a/src/com/android/phone/ecc/CountryEccInfo.java b/src/com/android/phone/ecc/CountryEccInfo.java
deleted file mode 100644
index 969901d..0000000
--- a/src/com/android/phone/ecc/CountryEccInfo.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.Collection;
-
-/**
- * ECC info of a country.
- */
-public class CountryEccInfo {
-    private final String mFallbackEcc;
-    private final EccInfo[] mEccInfoList;
-
-    public CountryEccInfo(String eccFallback, @NonNull Collection<EccInfo> eccInfoList) {
-        mFallbackEcc = eccFallback;
-        mEccInfoList = eccInfoList.toArray(new EccInfo[eccInfoList.size()]);
-    }
-
-    /**
-     * @return fallback ECC, null if not available.
-     */
-    public @Nullable String getFallbackEcc() {
-        return mFallbackEcc;
-    }
-
-    public @NonNull EccInfo[] getEccInfoList() {
-        return mEccInfoList.clone();
-    }
-}
diff --git a/src/com/android/phone/ecc/EccInfo.java b/src/com/android/phone/ecc/EccInfo.java
deleted file mode 100644
index fb41370..0000000
--- a/src/com/android/phone/ecc/EccInfo.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 androidx.annotation.NonNull;
-
-import java.util.Collection;
-
-/**
- * Emergency call code info.
- */
-public class EccInfo {
-    /**
-     * ECC Types.
-     */
-    public enum Type {
-        POLICE,
-        AMBULANCE,
-        FIRE,
-    }
-
-    private final String mNumber;
-    private final Type[] mTypes;
-
-    public EccInfo(@NonNull String number, @NonNull Type type) {
-        mNumber = number;
-        mTypes = new Type[]{ type };
-    }
-
-    public EccInfo(@NonNull String number, @NonNull Collection<Type> types) {
-        mNumber = number;
-        mTypes = types.toArray(new Type[types.size()]);
-    }
-
-    /**
-     * @return ECC number.
-     */
-    public @NonNull String getNumber() {
-        return mNumber;
-    }
-
-    /**
-     * Check whether the ECC number has any matches to the target type.
-     *
-     * @param target The target type to check.
-     * @return true if the target matches.
-     */
-    public boolean containsType(@NonNull Type target) {
-        for (Type type : mTypes) {
-            if (target.equals(type)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Get the types of the ECC number.
-     *
-     * @return Copied types array.
-     */
-    public Type[] getTypes() {
-        return mTypes.clone();
-    }
-
-    /**
-     * Get how many types the ECC number is.
-     *
-     * @return Count of types.
-     */
-    public int getTypesCount() {
-        return mTypes.length;
-    }
-}
diff --git a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java b/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
deleted file mode 100644
index 7d9b4f0..0000000
--- a/src/com/android/phone/ecc/IsoToEccProtobufRepository.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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 android.content.Context;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.zip.GZIPInputStream;
-
-/**
- * Provides a mapping table from country ISO to ECC info. The data is stored in Protocol Buffers
- * binary format, compressed with GZIP.
- */
-public class IsoToEccProtobufRepository implements IsoToEccRepository {
-    private static final String LOG_TAG = "EccRepository";
-
-    private static IsoToEccProtobufRepository sInstance;
-
-    /**
-     * Returns the singleton instance of IsoToEccProtobufRepository
-     */
-    public static synchronized IsoToEccProtobufRepository getInstance() {
-        if (sInstance == null) {
-            sInstance = new IsoToEccProtobufRepository();
-        }
-        return sInstance;
-    }
-
-    private final Map<String, CountryEccInfo> mEccTable = new HashMap<>();
-
-    private IsoToEccProtobufRepository() {
-    }
-
-    @Override
-    @Nullable
-    public CountryEccInfo getCountryEccInfo(@NonNull Context context, String iso)
-            throws IOException {
-        if (TextUtils.isEmpty(iso)) {
-            return null;
-        }
-
-        synchronized (mEccTable) {
-            return mEccTable.get(iso.toUpperCase());
-        }
-    }
-
-    /**
-     * Loads the mapping table.
-     */
-    public void loadMappingTable(@NonNull Context context) {
-        ProtobufEccData.AllInfo allEccData = null;
-
-        long startTime = SystemClock.uptimeMillis();
-        try {
-            allEccData = parseEccData(new BufferedInputStream(
-                    context.getAssets().open("eccdata")));
-        } catch (IOException e) {
-            Log.e(LOG_TAG, "Failed to retrieve ECC: ", e);
-        }
-        long endTime = SystemClock.uptimeMillis();
-
-        if (allEccData == null) {
-            return;
-        }
-
-        if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
-            Log.d(LOG_TAG, "Loading time = " + (endTime - startTime) + "ms"
-                    + ", Country Count = " + allEccData.getCountriesCount()
-                    + ", initialized = " + allEccData.isInitialized());
-        }
-
-        // Converts to run-time data from Protobuf data.
-        synchronized (mEccTable) {
-            mEccTable.clear();
-            for (ProtobufEccData.CountryInfo countryData : allEccData.getCountriesList()) {
-                if (countryData.hasIsoCode()) {
-                    CountryEccInfo countryInfo = loadCountryEccInfo(countryData);
-                    if (countryInfo != null) {
-                        mEccTable.put(countryData.getIsoCode().toUpperCase(), countryInfo);
-                    }
-                }
-            }
-        }
-    }
-
-    @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));
-    }
-
-    private EccInfo loadEccInfo(String isoCode, ProtobufEccData.EccInfo eccData) {
-        String phoneNumber = eccData.getPhoneNumber().trim();
-        if (phoneNumber.isEmpty()) {
-            Log.i(LOG_TAG, "Discard ecc " + phoneNumber
-                    + " for " + isoCode + " due to empty phone number");
-            return null;
-        }
-
-        ArraySet<EccInfo.Type> eccTypes = new ArraySet<>(eccData.getTypesCount());
-        for (ProtobufEccData.EccInfo.Type typeData : eccData.getTypesList()) {
-            switch (typeData) {
-                case POLICE:
-                    eccTypes.add(EccInfo.Type.POLICE);
-                    break;
-                case AMBULANCE:
-                    eccTypes.add(EccInfo.Type.AMBULANCE);
-                    break;
-                case FIRE:
-                    eccTypes.add(EccInfo.Type.FIRE);
-                    break;
-                default:
-                    // Ignores unknown types.
-            }
-        }
-
-        if (eccTypes.isEmpty()) {
-            Log.i(LOG_TAG, "Discard ecc " + phoneNumber
-                    + " for " + isoCode + " due to no valid type");
-            return null;
-        }
-        return new EccInfo(phoneNumber, eccTypes);
-    }
-
-    private CountryEccInfo loadCountryEccInfo(ProtobufEccData.CountryInfo countryData) {
-        ArrayMap<String, EccInfo> eccInfoMap = new ArrayMap<>(countryData.getEccsCount());
-        for (ProtobufEccData.EccInfo eccData : countryData.getEccsList()) {
-            EccInfo eccInfo = loadEccInfo(countryData.getIsoCode(), eccData);
-            String key = eccInfo.getNumber().trim();
-            EccInfo existentEccInfo = eccInfoMap.get(key);
-            if (existentEccInfo == null) {
-                eccInfoMap.put(key, eccInfo);
-            } else {
-                // Merges types of duplicated ECC info objects.
-                ArraySet<EccInfo.Type> eccTypes = new ArraySet<>(
-                        eccInfo.getTypesCount() + existentEccInfo.getTypesCount());
-                for (EccInfo.Type type : eccInfo.getTypes()) {
-                    eccTypes.add(type);
-                }
-                for (EccInfo.Type type : existentEccInfo.getTypes()) {
-                    eccTypes.add(type);
-                }
-                eccInfoMap.put(key, new EccInfo(eccInfo.getNumber(), eccTypes));
-            }
-        }
-
-        if (eccInfoMap.isEmpty() && !countryData.hasEccFallback()) {
-            Log.i(LOG_TAG, "Discard empty data for " + countryData.getIsoCode());
-            return null;
-        }
-        return new CountryEccInfo(countryData.getEccFallback(), eccInfoMap.values());
-    }
-}
diff --git a/src/com/android/phone/ecc/IsoToEccRepository.java b/src/com/android/phone/ecc/IsoToEccRepository.java
deleted file mode 100644
index 6d95af4..0000000
--- a/src/com/android/phone/ecc/IsoToEccRepository.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.io.IOException;
-
-/**
- * Data source for country ISO to ECC info list mapping.
- */
-public interface IsoToEccRepository {
-    /**
-     * Get available emergency numbers for given country ISO. Because the possible of IO wait
-     * (depends on the implementation), this method should not be called in the main thread.
-     *
-     * @param context The context used to access resources.
-     * @param iso For which ECC info list is returned.
-     * @return The ECC info of given ISO. Null if no match.
-     * @throws IOException if an error occurs while initialize the repository or retrieving
-     * the {@link CountryEccInfo}.
-     */
-    @Nullable CountryEccInfo getCountryEccInfo(@NonNull Context context, @Nullable String iso)
-            throws IOException;
-}
diff --git a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
index 670f98d..41063e2 100644
--- a/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
+++ b/src/com/android/phone/settings/PhoneAccountSettingsFragment.java
@@ -18,6 +18,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -76,6 +77,15 @@
     private SwitchPreference mSipReceiveCallsPreference;
     private SipPreferences mSipPreferences;
 
+    private final SubscriptionManager.OnSubscriptionsChangedListener
+            mOnSubscriptionsChangeListener =
+            new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            updateAccounts();
+        }
+    };
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -122,34 +132,8 @@
          */
         mAccountList = (PreferenceCategory) getPreferenceScreen().findPreference(
                 ACCOUNTS_LIST_CATEGORY_KEY);
-        List<PhoneAccountHandle> allNonSimAccounts =
-                getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
-        // Check to see if we should show the entire section at all.
-        if (shouldShowConnectionServiceList(allNonSimAccounts)) {
-            List<PhoneAccountHandle> enabledAccounts =
-                    getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
-            // Initialize the account list with the set of enabled & SIM accounts.
-            initAccountList(enabledAccounts);
 
-            mDefaultOutgoingAccount = (AccountSelectionPreference)
-                    getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
-            mDefaultOutgoingAccount.setListener(this);
-
-            // Only show the 'Make Calls With..." option if there are multiple accounts.
-            if (enabledAccounts.size() > 1) {
-                updateDefaultOutgoingAccountsModel();
-            } else {
-                mAccountList.removePreference(mDefaultOutgoingAccount);
-            }
-
-            Preference allAccounts = getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY);
-            // If there are no third party (nonSim) accounts, then don't show enable/disable dialog.
-            if (allNonSimAccounts.isEmpty() && allAccounts != null) {
-                mAccountList.removePreference(allAccounts);
-            }
-        } else {
-            getPreferenceScreen().removePreference(mAccountList);
-        }
+        updateAccounts();
 
         if (isPrimaryUser() && SipUtil.isVoipSupported(getActivity())) {
             mSipPreferences = new SipPreferences(getActivity());
@@ -183,6 +167,16 @@
             getPreferenceScreen().removePreference(
                     getPreferenceScreen().findPreference(SIP_SETTINGS_CATEGORY_PREF_KEY));
         }
+
+        SubscriptionManager.from(getActivity()).addOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangeListener);
+    }
+
+    @Override
+    public void onPause() {
+        SubscriptionManager.from(getActivity()).removeOnSubscriptionsChangedListener(
+                mOnSubscriptionsChangeListener);
+        super.onPause();
     }
 
     /**
@@ -391,6 +385,44 @@
         return mTelephonyManager.isMultiSimEnabled() || allNonSimAccounts.size() > 0;
     }
 
+    private void updateAccounts() {
+        if (mAccountList != null) {
+            mAccountList.removeAll();
+            List<PhoneAccountHandle> allNonSimAccounts =
+                    getCallingAccounts(false /* includeSims */, true /* includeDisabled */);
+            // Check to see if we should show the entire section at all.
+            if (shouldShowConnectionServiceList(allNonSimAccounts)) {
+                List<PhoneAccountHandle> enabledAccounts =
+                        getCallingAccounts(true /* includeSims */, false /* includeDisabled */);
+                // Initialize the account list with the set of enabled & SIM accounts.
+                initAccountList(enabledAccounts);
+
+                mDefaultOutgoingAccount = (AccountSelectionPreference)
+                        getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY);
+                if (mDefaultOutgoingAccount != null) {
+                    mDefaultOutgoingAccount.setListener(this);
+
+                    // Only show the 'Make Calls With..." option if there are multiple accounts.
+                    if (enabledAccounts.size() > 1) {
+                        updateDefaultOutgoingAccountsModel();
+                    } else {
+                        mAccountList.removePreference(mDefaultOutgoingAccount);
+                    }
+                }
+
+                Preference allAccounts =
+                        getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY);
+                // If there are no third party (nonSim) accounts,
+                // then don't show enable/disable dialog.
+                if (allNonSimAccounts.isEmpty() && allAccounts != null) {
+                    mAccountList.removePreference(allAccounts);
+                }
+            } else {
+                getPreferenceScreen().removePreference(mAccountList);
+            }
+        }
+    }
+
     private List<PhoneAccountHandle> getCallingAccounts(
             boolean includeSims, boolean includeDisabledAccounts) {
         PhoneAccountHandle emergencyAccountHandle = getEmergencyPhoneAccount();
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 37c5d7c..f925dd6 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -46,6 +46,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -114,10 +115,10 @@
             }
 
             try {
-                mMmTelManager = ImsMmTelManager.createForSubscriptionId(mContext, getSubId());
+                mMmTelManager = ImsMmTelManager.createForSubscriptionId(getSubId());
             } catch (IllegalArgumentException e) {
                 Log.i(this, "Not registering MmTel capabilities listener because the subid '"
-                        + getSubId() + "' is invalid");
+                        + getSubId() + "' is invalid: " + e.getMessage());
                 return;
             }
 
@@ -151,9 +152,13 @@
             try {
                 mMmTelManager.registerMmTelCapabilityCallback(mContext.getMainExecutor(),
                         mMmtelCapabilityCallback);
-            } catch (IllegalStateException e) {
+            } catch (ImsException e) {
                 Log.w(this, "registerMmTelCapabilityCallback: registration failed, no ImsService"
-                        + " available.");
+                        + " available. Exception: " + e.getMessage());
+                return;
+            } catch (IllegalArgumentException e) {
+                Log.w(this, "registerMmTelCapabilityCallback: registration failed, invalid"
+                        + " subscription, Exception" + e.getMessage());
                 return;
             }
         }
@@ -316,6 +321,8 @@
                     && isImsVoiceAvailable()) {
                 capabilities |= PhoneAccount.CAPABILITY_RTT;
                 mIsRttCapable = true;
+            } else {
+                mIsRttCapable = false;
             }
 
             extras.putBoolean(PhoneAccount.EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK,
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index d2ba8f1..3886e58 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -46,6 +46,7 @@
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallFailCause;
 import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.Call.HoldingRequestState;
 import com.android.internal.telephony.Connection.Capability;
 import com.android.internal.telephony.Connection.PostDialListener;
 import com.android.internal.telephony.Phone;
@@ -952,6 +953,7 @@
                 // instead of actually putting it on hold.
                 if (ringingCall.getState() != Call.State.WAITING) {
                     phone.switchHoldingAndActive();
+                    mOriginalConnection.getCall().updateHoldingRequestState(HoldingRequestState.STARTED);
                 }
 
                 // TODO: Cdma calls are slightly different.
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index ab9e211..e0db44e 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -71,6 +71,8 @@
 import java.util.Queue;
 import java.util.regex.Pattern;
 
+import javax.annotation.Nullable;
+
 /**
  * Service for making GSM and CDMA connections.
  */
@@ -321,8 +323,8 @@
         if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
             // TODO: We don't check for SecurityException here (requires
             // CALL_PRIVILEGED permission).
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), false,
-                    handle.getSchemeSpecificPart());
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+                    false /* isEmergencyCall */, null /* not an emergency call */);
             if (phone == null) {
                 Log.d(this, "onCreateOutgoingConnection, phone is null");
                 return Connection.createFailedConnection(
@@ -360,8 +362,8 @@
                                 "Unable to parse number"));
             }
 
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(), false,
-                    handle.getSchemeSpecificPart());
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+                    false /* isEmergencyCall*/, null /* not an emergency call */);
             if (phone != null && CDMA_ACTIVATION_CODE_REGEX_PATTERN.matcher(number).matches()) {
                 // Obtain the configuration for the outgoing phone's SIM. If the outgoing number
                 // matches the *228 regex pattern, fail the call. This number is used for OTASP, and
@@ -468,7 +470,8 @@
 
             // Get the right phone object from the account data passed in.
             final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
-                    handle.getSchemeSpecificPart());
+                    /* Note: when not an emergency, handle can be null for unknown callers */
+                    handle == null ? null : handle.getSchemeSpecificPart());
             Connection resultConnection = getTelephonyConnection(request, numberToDial,
                     isEmergencyNumber, handle, phone);
             // If there was a failure, the resulting connection will not be a TelephonyConnection,
@@ -512,8 +515,9 @@
         if (isRadioReady) {
             // Get the right phone object since the radio has been turned on
             // successfully.
-            final Phone phone = getPhoneForAccount(request.getAccountHandle(),
-                    isEmergencyNumber, handle.getSchemeSpecificPart());
+            final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
+                    /* Note: when not an emergency, handle can be null for unknown callers */
+                    handle == null ? null : handle.getSchemeSpecificPart());
             // If the PhoneType of the Phone being used is different than the Default Phone, then we
             // need create a new Connection using that PhoneType and replace it in Telecom.
             if (phone.getPhoneType() != originalPhoneType) {
@@ -732,7 +736,8 @@
             isEmergency = true;
         }
         Phone phone = getPhoneForAccount(accountHandle, isEmergency,
-                request.getAddress().getSchemeSpecificPart());
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
         if (phone == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -844,7 +849,8 @@
             isEmergency = true;
         }
         Phone phone = getPhoneForAccount(accountHandle, isEmergency,
-                request.getAddress().getSchemeSpecificPart());
+                /* Note: when not an emergency, handle can be null for unknown callers */
+                request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
         if (phone == null) {
             return Connection.createFailedConnection(
                     DisconnectCauseUtil.toTelecomDisconnectCause(
@@ -1234,8 +1240,17 @@
         return false;
     }
 
+    /**
+     * Determines which {@link Phone} will be used to place the call.
+     * @param accountHandle The {@link PhoneAccountHandle} which was sent from Telecom to place the
+     *      call on.
+     * @param isEmergency {@code true} if this is an emergency call, {@code false} otherwise.
+     * @param emergencyNumberAddress When {@code isEmergency} is {@code true}, will be the phone
+     *      of the emergency call.  Otherwise, this can be {@code null}  .
+     * @return
+     */
     private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency,
-                                     String emergencyNumberAddress) {
+                                     @Nullable String emergencyNumberAddress) {
         Phone chosenPhone = null;
         int subId = PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
index fea2bf8..0ff6cc1 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsCallingActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -162,12 +163,12 @@
         mListView = (ListView) findViewById(R.id.cap_cb_list);
         mListView.setAdapter(mCapabiltyEventAdapter);
         try {
-            mImsManager = ImsMmTelManager.createForSubscriptionId(this,
+            mImsManager = ImsMmTelManager.createForSubscriptionId(
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
             Log.i("ImsCallingActivity", "onResume");
             mImsManager.registerMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback);
-        } catch (IllegalArgumentException e) {
-            Log.w("ImsCallingActivity", "illegal subscription ID.");
+        } catch (IllegalArgumentException | ImsException e) {
+            Log.w("ImsCallingActivity", "Exception: " + e.getMessage());
         }
     }
 
diff --git a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
index 3317ff1..e4a4e6f 100644
--- a/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
+++ b/testapps/ImsTestService/src/com/android/phone/testapps/imstestapp/ImsRegistrationActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.telephony.SubscriptionManager;
+import android.telephony.ims.ImsException;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -177,10 +178,10 @@
         mListView = (ListView) findViewById(R.id.reg_cb_list);
         mListView.setAdapter(mRegItemAdapter);
         try {
-            mImsManager = ImsMmTelManager.createForSubscriptionId(this,
+            mImsManager = ImsMmTelManager.createForSubscriptionId(
                     SubscriptionManager.getDefaultVoiceSubscriptionId());
             mImsManager.registerImsRegistrationCallback(getMainExecutor(), mRegistrationCallback);
-        } catch (IllegalArgumentException e) {
+        } catch (IllegalArgumentException | ImsException e) {
             Log.w("ImsCallingActivity", "illegal subscription ID.");
         }
 
diff --git a/testapps/TelephonyRegistryTestApp/AndroidManifest.xml b/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
index 708ea66..1cfd3ba 100644
--- a/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
+++ b/testapps/TelephonyRegistryTestApp/AndroidManifest.xml
@@ -19,6 +19,7 @@
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE"/>
     <application android:label="TelephonyRegistryTestApp">
         <activity
             android:name=".TelephonyRegistryTestApp"