Merge "Remove dependence on Connection.Listener in Telephony."
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 39bca72..7a99569 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -441,7 +441,7 @@
     <string name="deleting_fdn_contact" msgid="5669163206349319969">"正在删除固定拨号联系人..."</string>
     <string name="fdn_contact_deleted" msgid="7154162327112259569">"已删除固定拨号联系人。"</string>
     <string name="pin2_invalid" msgid="5470854099230755944">"固定拨号未更新,因为输入的 PIN 码有误。"</string>
-    <string name="fdn_invalid_number" msgid="2062898833049589309">"未能更新 FDN,因为号码超过 20 位数。"</string>
+    <string name="fdn_invalid_number" msgid="2062898833049589309">"未能更新 FDN,因为号码超过 <xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> 位数。"</string>
     <string name="pin2_or_fdn_invalid" msgid="6025144083384701197">"固定拨号未更新。PIN2 码有误,或电话号码遭拒。"</string>
     <string name="fdn_failed" msgid="540018079008319747">"固定拨号操作失败。"</string>
     <string name="simContacts_emptyLoading" msgid="2203331234764498011">"正在从SIM卡读取..."</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 14dd60e..7d2072c 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -443,7 +443,7 @@
     <string name="deleting_fdn_contact" msgid="5669163206349319969">"正在刪除固定撥號…"</string>
     <string name="fdn_contact_deleted" msgid="7154162327112259569">"已刪除固定撥號。"</string>
     <string name="pin2_invalid" msgid="5470854099230755944">"您所輸入的 PIN 不正確,因此未更新 FDN。"</string>
-    <string name="fdn_invalid_number" msgid="2062898833049589309">"固定撥號的號碼超過 20 位數,因此無法更新。"</string>
+    <string name="fdn_invalid_number" msgid="2062898833049589309">"固定撥號的號碼超過 <xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> 位數,因此無法更新。"</string>
     <string name="pin2_or_fdn_invalid" msgid="6025144083384701197">"未更新 FDN。可能是因為 PIN2 碼不正確或電話號碼遭拒。"</string>
     <string name="fdn_failed" msgid="540018079008319747">"FDN 操作失敗。"</string>
     <string name="simContacts_emptyLoading" msgid="2203331234764498011">"正在從 SIM 卡讀取…"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7dae45d..689e239 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -977,7 +977,7 @@
     <!-- FDN settings: error message displayed in a popup (toast) -->
     <string name="pin2_invalid">FDN wasn\'t updated because you typed an incorrect PIN.</string>
     <!-- FDN settings: error message displayed in a popup (toast) -->
-    <string name="fdn_invalid_number">FDN wasn\'t updated because the number exceeds 20 digits.</string>
+    <string name="fdn_invalid_number">FDN wasn\'t updated because the number exceeds <xliff:g id="FDN_NUMBER_LIMIT_LENGTH">%d</xliff:g> digits.</string>
     <!-- FDN settings: error message displayed in a popup (toast), when the entered
          FDN number was inappropriate, OR, PIN2 the user entered was incorrect.
          Because of API restriction, there's no way to determine which is the exact
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 077652f..1d0138b 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -568,6 +568,13 @@
             configPackagename = mPlatformCarrierConfigPackage;
             configToSend = mConfigFromDefaultApp[phoneId];
         }
+
+        // mOverrideConfigs is for testing. And it will override current configs.
+        PersistableBundle config = mOverrideConfigs[phoneId];
+        if (config != null) {
+            configToSend.putAll(config);
+        }
+
         mSubscriptionInfoUpdater.updateSubscriptionByCarrierConfigAndNotifyComplete(
                 phoneId, configPackagename, configToSend,
                 mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1));
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 4a75fd0..337d998 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -106,6 +106,7 @@
 import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -142,8 +143,6 @@
 import com.android.internal.telephony.RIL;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.ServiceStateTracker;
-import com.android.internal.telephony.SmsApplication;
-import com.android.internal.telephony.SmsApplication.SmsApplicationData;
 import com.android.internal.telephony.SmsController;
 import com.android.internal.telephony.SmsPermissions;
 import com.android.internal.telephony.SubscriptionController;
@@ -176,7 +175,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -2906,6 +2904,10 @@
     public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
             throws RemoteException {
         enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS not available on device.");
+        }
         final long token = Binder.clearCallingIdentity();
         try {
             // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -2942,6 +2944,10 @@
     public void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
             throws RemoteException {
         enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
+        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS not available on device.");
+        }
         // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
         final long token = Binder.clearCallingIdentity();
         try {
@@ -3007,6 +3013,44 @@
         }
     }
 
+    /**
+     * Determines if the MmTel feature capability is supported by the carrier configuration for this
+     * subscription.
+     * @param subId The subscription to use to check the configuration.
+     * @param callback The callback that will be used to send the result.
+     * @param capability The MmTelFeature capability that will be used to send the result.
+     * @param transportType The transport type of the MmTelFeature capability.
+     */
+    @Override
+    public void isMmTelCapabilitySupported(int subId, IIntegerConsumer callback, int capability,
+            int transportType) {
+        enforceReadPrivilegedPermission("isMmTelCapabilitySupported");
+        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS not available on device.");
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            int slotId = getSlotIndex(subId);
+            if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                Log.w(LOG_TAG, "isMmTelCapabilitySupported: called with an inactive subscription '"
+                        + subId + "'");
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION);
+            }
+            ImsManager.getInstance(mApp, slotId).isSupported(capability,
+                    transportType, aBoolean -> {
+                        try {
+                            callback.accept((aBoolean == null) ? 0 : (aBoolean ? 1 : 0));
+                        } catch (RemoteException e) {
+                            Log.w(LOG_TAG, "isMmTelCapabilitySupported: remote caller is not "
+                                    + "running. Ignore");
+                        }
+                    });
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @Override
     public boolean isAdvancedCallingSettingEnabled(int subId) {
         enforceReadPrivilegedPermission("enforceReadPrivilegedPermission");
@@ -4473,6 +4517,40 @@
         }
     }
 
+    /**
+     * Get the MmTelFeature state associated with the requested subscription id.
+     * @param subId The subscription that the MmTelFeature is associated with.
+     * @param callback A callback with an integer containing the
+     * {@link android.telephony.ims.feature.ImsFeature.ImsState} associated with the MmTelFeature.
+     */
+    @Override
+    public void getImsMmTelFeatureState(int subId, IIntegerConsumer callback) {
+        enforceReadPrivilegedPermission("getImsMmTelFeatureState");
+        if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+            throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+                    "IMS not available on device.");
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            int slotId = getSlotIndex(subId);
+            if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                Log.w(LOG_TAG, "getImsMmTelFeatureState: called with an inactive subscription '"
+                        + subId + "'");
+                throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION);
+            }
+            ImsManager.getInstance(mApp, slotId).getImsServiceState(anInteger -> {
+                try {
+                    callback.accept(anInteger == null ? ImsFeature.STATE_UNAVAILABLE : anInteger);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "getImsMmTelFeatureState: remote caller is no longer running. "
+                            + "Ignore");
+                }
+            });
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     public void setImsRegistrationState(boolean registered) {
         enforceModifyPermission();
 
@@ -5611,6 +5689,11 @@
             // in and combined with those stale ones. In case this happens again,
             // user can reset all network settings which will clean up this table.
             cleanUpSmsRawTable(getDefaultPhone().getContext());
+            // Clean up IMS settings as well here.
+            int slotId = getSlotIndex(subId);
+            if (slotId > SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                ImsManager.getInstance(mApp, slotId).factoryReset();
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -6832,75 +6915,6 @@
         }
     }
 
-    private void ensureUserRunning(int userId) {
-        if (!mUserManager.isUserRunning(userId)) {
-            throw new IllegalStateException("User " + userId + " does not exist or not running");
-        }
-    }
-
-    /**
-     * Returns a list of SMS apps on a given user.
-     *
-     * Only the shell user (UID 2000 or 0) can call it.
-     * Target user must be running.
-     */
-    @Override
-    public String[] getSmsApps(int userId) {
-        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "getSmsApps");
-        ensureUserRunning(userId);
-
-        final Collection<SmsApplicationData> apps =
-                SmsApplication.getApplicationCollectionAsUser(mApp, userId);
-
-        String[] ret = new String[apps.size()];
-        int i = 0;
-        for (SmsApplicationData app : apps) {
-            ret[i++] = app.mPackageName;
-        }
-        return ret;
-    }
-
-    /**
-     * Returns the default SMS app package name on a given user.
-     *
-     * Only the shell user (UID 2000 or 0) can call it.
-     * Target user must be running.
-     */
-    @Override
-    public String getDefaultSmsApp(int userId) {
-        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "getDefaultSmsApp");
-        ensureUserRunning(userId);
-
-        final ComponentName cn = SmsApplication.getDefaultSmsApplicationAsUser(mApp,
-                /* updateIfNeeded= */ true, userId);
-        return cn == null ? null : cn.getPackageName();
-    }
-
-    /**
-     * Set a package as the default SMS app on a given user.
-     *
-     * Only the shell user (UID 2000 or 0) can call it.
-     * Target user must be running.
-     */
-    @Override
-    public void setDefaultSmsApp(int userId, String packageName) {
-        TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "setDefaultSmsApp");
-        ensureUserRunning(userId);
-
-        boolean found = false;
-        for (String pkg : getSmsApps(userId)) {
-            if (TextUtils.equals(packageName, pkg)) {
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            throw new IllegalArgumentException("Package " + packageName + " is not an SMS app");
-        }
-
-        SmsApplication.setDefaultApplicationAsUser(packageName, mApp, userId);
-    }
-
     @Override
     public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
             String callingPackage) {
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index a34abc0..d8d1717 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -20,7 +20,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ShellCommand;
-import android.os.UserHandle;
 import android.telephony.SubscriptionManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.util.Log;
@@ -45,7 +44,6 @@
     private static final int DEFAULT_PHONE_ID = 0;
 
     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 EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
 
@@ -58,10 +56,6 @@
     // support CEP data.
     private static final String IMS_CEP = "conference-event-package";
 
-    private static final String SMS_GET_APPS = "get-apps";
-    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";
 
@@ -82,9 +76,6 @@
             case IMS_SUBCOMMAND: {
                 return handleImsCommand();
             }
-            case SMS_SUBCOMMAND: {
-                return handleSmsCommand();
-            }
             case NUMBER_VERIFICATION_SUBCOMMAND:
                 return handleNumberVerificationCommand();
             case EMERGENCY_NUMBER_TEST_MODE:
@@ -103,12 +94,9 @@
         pw.println("    Print this help text.");
         pw.println("  ims");
         pw.println("    IMS Commands.");
-        pw.println("  sms");
-        pw.println("    SMS Commands.");
         pw.println("  emergency-number-test-mode");
         pw.println("    Emergency Number Test Mode Commands.");
         onHelpIms();
-        onHelpSms();
         onHelpEmergencyNumber();
     }
 
@@ -139,18 +127,6 @@
         pw.println("    enables or disables handling or network conference event package data.");
     }
 
-    private void onHelpSms() {
-        PrintWriter pw = getOutPrintWriter();
-        pw.println("SMS Commands:");
-        pw.println("  sms get-apps [--user USER_ID]");
-        pw.println("    Print all SMS apps on a user.");
-        pw.println("  sms get-default-app [--user USER_ID]");
-        pw.println("    Get the default SMS app.");
-        pw.println("  sms set-default-app [--user USER_ID] PACKAGE_NAME");
-        pw.println("    Set PACKAGE_NAME as the default SMS app.");
-    }
-
-
     private void onHelpNumberVerification() {
         PrintWriter pw = getOutPrintWriter();
         pw.println("Number verification commands");
@@ -501,87 +477,6 @@
         return slotId;
     }
 
-    private int handleSmsCommand() {
-        String arg = getNextArg();
-        if (arg == null) {
-            onHelpSms();
-            return 0;
-        }
-
-        try {
-            switch (arg) {
-                case SMS_GET_APPS: {
-                    return handleSmsGetApps();
-                }
-                case SMS_GET_DEFAULT_APP: {
-                    return handleSmsGetDefaultApp();
-                }
-                case SMS_SET_DEFAULT_APP: {
-                    return handleSmsSetDefaultApp();
-                }
-                default:
-                    getErrPrintWriter().println("Unknown command " + arg);
-            }
-        } catch (RemoteException e) {
-            getErrPrintWriter().println("RemoteException: " + e.getMessage());
-        }
-
-        return -1;
-    }
-
-    private int maybeParseUserIdArg() {
-        int userId = UserHandle.USER_SYSTEM;
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            switch (opt) {
-                case "--user": {
-                    try {
-                        userId = Integer.parseInt(getNextArgRequired());
-                    } catch (NumberFormatException e) {
-                        getErrPrintWriter().println("Invalid user ID for --user");
-                        return -1;
-                    }
-                    break;
-                }
-            }
-        }
-        return userId;
-    }
-
-    private int handleSmsGetApps() throws RemoteException {
-        final int userId = maybeParseUserIdArg();
-        if (userId < 0) {
-            return -1;
-        }
-
-        for (String packageName : mInterface.getSmsApps(userId)) {
-            getOutPrintWriter().println(packageName);
-        }
-        return 0;
-    }
-
-    private int handleSmsGetDefaultApp() throws RemoteException {
-        final int userId = maybeParseUserIdArg();
-        if (userId < 0) {
-            return -1;
-        }
-
-        getOutPrintWriter().println(mInterface.getDefaultSmsApp(userId));
-        return 0;
-    }
-
-    private int handleSmsSetDefaultApp() throws RemoteException {
-        final int userId = maybeParseUserIdArg();
-        if (userId < 0) {
-            return -1;
-        }
-
-        String packageName = getNextArgRequired();
-        mInterface.setDefaultSmsApp(userId, packageName);
-        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
diff --git a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
index c358e27..0eda140 100644
--- a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
@@ -29,6 +29,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.provider.ContactsContract.CommonDataKinds;
 import android.telephony.PhoneNumberUtils;
 import android.text.Editable;
@@ -52,6 +53,7 @@
 import com.android.phone.PhoneGlobals;
 import com.android.phone.R;
 import com.android.phone.SubscriptionInfoHelper;
+import android.telephony.CarrierConfigManager;
 
 /**
  * Activity to let the user add or edit an FDN contact.
@@ -100,6 +102,7 @@
     }
     /** flag to track saving state */
     private boolean mDataBusy;
+    private int mFdnNumberLimitLength = 20;
 
     @Override
     protected void onCreate(Bundle icicle) {
@@ -111,6 +114,17 @@
         setContentView(R.layout.edit_fdn_contact_screen);
         setupView();
         setTitle(mAddContact ? R.string.add_fdn_contact : R.string.edit_fdn_contact);
+        PersistableBundle b = null;
+        if (mSubscriptionInfoHelper.hasSubId()) {
+            b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+                    mSubscriptionInfoHelper.getSubId());
+        } else {
+            b = PhoneGlobals.getInstance().getCarrierConfig();
+        }
+        if (b != null) {
+            mFdnNumberLimitLength = b.getInt(
+                    CarrierConfigManager.KEY_FDN_NUMBER_LENGTH_LIMIT_INT);
+        }
 
         displayProgress(false);
     }
@@ -294,7 +308,7 @@
       * TODO: Fix this logic.
       */
      private boolean isValidNumber(String number) {
-         return (number.length() <= 20) && (number.length() > 0);
+         return (number.length() <= mFdnNumberLimitLength) && (number.length() > 0);
      }
 
 
@@ -397,7 +411,8 @@
         } else {
             if (DBG) log("handleResult: failed!");
             if (invalidNumber) {
-                showStatus(getResources().getText(R.string.fdn_invalid_number));
+                showStatus(getResources().getString(R.string.fdn_invalid_number,
+                        mFdnNumberLimitLength));
             } else {
                if (PhoneFactory.getDefaultPhone().getIccCard().getIccPin2Blocked()) {
                     showStatus(getResources().getText(R.string.fdn_enable_puk2_requested));