Merge "Split TeleService into a client apk and a lib."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1321ace..22845e0 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -48,3 +48,5 @@
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.services.telephony.common_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/telephony-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ims-common.jar)
diff --git a/apex/Android.bp b/apex/Android.bp
index 4985f40..86ebe3a 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -6,7 +6,7 @@
     // optional. if unspecified, a default one is auto-generated
     androidManifest: "AndroidManifest.xml",
 
-    //java_libs: ["telephony-common", "ims-common", "voip-common"],
+    java_libs: ["telephony-common", "ims-common"],
     //apps: ["TeleService", "StkLib", "ONSLib"],
     apps: ["StkLib"],
 
@@ -25,4 +25,4 @@
     // This will use com.android.telephony.x509.pem (the cert) and
     // com.android.telephony.pk8 (the private key)
     certificate: "com.android.telephony",
-}
\ No newline at end of file
+}
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 70d1c24..192038d 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -107,21 +107,21 @@
     <string name="sum_cfu_enabled_indicator" msgid="9030139213402432776">"Deviazione di tutte le chiamate"</string>
     <string name="sum_cfu_enabled" msgid="5806923046528144526">"Deviazione di tutte le chiamate al numero <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
     <string name="sum_cfu_enabled_no_number" msgid="7287752761743377930">"Numero non disponibile"</string>
-    <string name="sum_cfu_disabled" msgid="5010617134210809853">"Off"</string>
+    <string name="sum_cfu_disabled" msgid="5010617134210809853">"OFF"</string>
     <string name="labelCFB" msgid="615265213360512768">"Se occupato"</string>
     <string name="messageCFB" msgid="1958017270393563388">"Numero se occupato"</string>
     <string name="sum_cfb_enabled" msgid="332037613072049492">"Deviazione al numero <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
-    <string name="sum_cfb_disabled" msgid="3589913334164866035">"Off"</string>
+    <string name="sum_cfb_disabled" msgid="3589913334164866035">"OFF"</string>
     <string name="disable_cfb_forbidden" msgid="4831494744351633961">"Il tuo operatore non supporta la disattivazione dell\'inoltro chiamate quando il telefono è occupato."</string>
     <string name="labelCFNRy" msgid="3403533792248457946">"Se non si risponde"</string>
     <string name="messageCFNRy" msgid="7644434155765359009">"Numero se non si risponde"</string>
     <string name="sum_cfnry_enabled" msgid="3000500837493854799">"Deviazione al numero <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
-    <string name="sum_cfnry_disabled" msgid="1990563512406017880">"Off"</string>
+    <string name="sum_cfnry_disabled" msgid="1990563512406017880">"OFF"</string>
     <string name="disable_cfnry_forbidden" msgid="3174731413216550689">"Il tuo operatore non supporta la disattivazione dell\'inoltro chiamate quando il telefono non risponde."</string>
     <string name="labelCFNRc" msgid="4163399350778066013">"Se non raggiungibile"</string>
     <string name="messageCFNRc" msgid="6980340731313007250">"Numero se non raggiungibile"</string>
     <string name="sum_cfnrc_enabled" msgid="1799069234006073477">"Deviazione al numero <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
-    <string name="sum_cfnrc_disabled" msgid="739289696796917683">"Off"</string>
+    <string name="sum_cfnrc_disabled" msgid="739289696796917683">"OFF"</string>
     <string name="disable_cfnrc_forbidden" msgid="775348748084726890">"Il tuo operatore non supporta la disattivazione dell\'inoltro chiamate quando il telefono non è raggiungibile."</string>
     <string name="updating_title" msgid="6130548922615719689">"Impostazioni chiamate"</string>
     <string name="call_settings_admin_user_only" msgid="7238947387649986286">"Le impostazioni delle chiamate possono essere modificate solo dall\'utente amministratore."</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 9841a82..13dcaa7 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -20,6 +20,7 @@
 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -94,6 +95,8 @@
     private PersistableBundle[] mConfigFromDefaultApp;
     // Carrier configs from privileged carrier config app, indexed by phoneID.
     private PersistableBundle[] mConfigFromCarrierApp;
+    // Persistent Carrier configs that are provided via the override test API, indexed by phone ID.
+    private PersistableBundle[] mPersistentOverrideConfigs;
     // Carrier configs that are provided via the override test API, indexed by phone ID.
     private PersistableBundle[] mOverrideConfigs;
     // Service connection for binding to config app.
@@ -151,6 +154,8 @@
     private static final String TAG_VERSION = "package_version";
     private static final String TAG_BUNDLE = "bundle_data";
 
+    private static final String OVERRIDE_PACKAGE_ADDITION = "-override";
+
     // SharedPreferences key for last known build fingerprint.
     private static final String KEY_FINGERPRINT = "build_fingerprint";
 
@@ -220,8 +225,17 @@
 
                 case EVENT_DO_FETCH_DEFAULT:
                 {
-                    final PersistableBundle config =
-                            restoreConfigFromXml(mPlatformCarrierConfigPackage, phoneId);
+                    // Restore persistent override values.
+                    PersistableBundle config = restoreConfigFromXml(
+                            mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId);
+                    if (config != null) {
+                        log("Loaded persistent override config from XML. package="
+                                + mPlatformCarrierConfigPackage
+                                + " phoneId=" + phoneId);
+                        mPersistentOverrideConfigs[phoneId] = config;
+                    }
+
+                    config = restoreConfigFromXml(mPlatformCarrierConfigPackage, "", phoneId);
                     if (config != null) {
                         log(
                                 "Loaded config from XML. package="
@@ -283,7 +297,7 @@
                                     }
                                     PersistableBundle config =
                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
-                                    saveConfigToXml(mPlatformCarrierConfigPackage, phoneId,
+                                    saveConfigToXml(mPlatformCarrierConfigPackage, "", phoneId,
                                         carrierId, config);
                                     mConfigFromDefaultApp[phoneId] = config;
                                     sendMessage(
@@ -351,7 +365,7 @@
                 {
                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
                     final PersistableBundle config =
-                            restoreConfigFromXml(carrierPackageName, phoneId);
+                            restoreConfigFromXml(carrierPackageName, "", phoneId);
                     if (config != null) {
                         log(
                                 "Loaded config from XML. package="
@@ -414,8 +428,8 @@
                                     }
                                     PersistableBundle config =
                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
-                                    saveConfigToXml(getCarrierPackageForPhoneId(phoneId), phoneId,
-                                        carrierId, config);
+                                    saveConfigToXml(getCarrierPackageForPhoneId(phoneId), "",
+                                            phoneId, carrierId, config);
                                     mConfigFromCarrierApp[phoneId] = config;
                                     sendMessage(
                                             obtainMessage(
@@ -528,6 +542,7 @@
         int numPhones = TelephonyManager.from(context).getSupportedModemCount();
         mConfigFromDefaultApp = new PersistableBundle[numPhones];
         mConfigFromCarrierApp = new PersistableBundle[numPhones];
+        mPersistentOverrideConfigs = new PersistableBundle[numPhones];
         mOverrideConfigs = new PersistableBundle[numPhones];
         mServiceConnection = new CarrierServiceConnection[numPhones];
         mHasSentConfigChange = new boolean[numPhones];
@@ -737,12 +752,13 @@
      * In case of errors or invalid input, no file will be written.
      *
      * @param packageName the name of the package from which we fetched this bundle.
+     * @param extraString An extra string to be used in the XML file name.
      * @param phoneId the phone ID.
      * @param carrierId contains all carrier-identifying information.
      * @param config the bundle to be written. Null will be treated as an empty bundle.
      */
-    private void saveConfigToXml(String packageName, int phoneId, CarrierIdentifier carrierId,
-        PersistableBundle config) {
+    private void saveConfigToXml(String packageName, @NonNull String extraString, int phoneId,
+            CarrierIdentifier carrierId, PersistableBundle config) {
         if (SubscriptionManager.getSimStateForSlotIndex(phoneId)
                 != TelephonyManager.SIM_STATE_LOADED) {
             loge("Skip save config because SIM records are not loaded.");
@@ -776,7 +792,7 @@
         try {
             outFile = new FileOutputStream(
                     new File(mContext.getFilesDir(),
-                            getFilenameForConfig(packageName, iccid, cid)));
+                            getFilenameForConfig(packageName, extraString, iccid, cid)));
             FastXmlSerializer out = new FastXmlSerializer();
             out.setOutput(outFile, "utf-8");
             out.startDocument("utf-8", true);
@@ -810,11 +826,13 @@
      * current version, then null will be returned.
      *
      * @param packageName the name of the package from which we fetched this bundle.
+     * @param extraString An extra string to be used in the XML file name.
      * @param phoneId the phone ID.
      * @return the bundle from the XML file. Returns null if there is no saved config, the saved
      *         version does not match, or reading config fails.
      */
-    private PersistableBundle restoreConfigFromXml(String packageName, int phoneId) {
+    private PersistableBundle restoreConfigFromXml(String packageName, @NonNull String extraString,
+            int phoneId) {
         final String version = getPackageVersion(packageName);
         if (version == null) {
             loge("Failed to get package version for: " + packageName);
@@ -834,11 +852,12 @@
         }
 
         PersistableBundle restoredBundle = null;
+        File file = null;
         FileInputStream inFile = null;
         try {
-            inFile = new FileInputStream(
-                    new File(mContext.getFilesDir(),
-                            getFilenameForConfig(packageName, iccid, cid)));
+            file = new File(mContext.getFilesDir(),
+                    getFilenameForConfig(packageName, extraString, iccid, cid));
+            inFile = new FileInputStream(file);
             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
             parser.setInput(inFile, "utf-8");
 
@@ -860,7 +879,9 @@
             inFile.close();
         }
         catch (FileNotFoundException e) {
-            loge(e.toString());
+            // Missing file is normal occurrence that might occur with a new sim or when restoring
+            // an override file during boot and should not be treated as an error.
+            if (file != null) log("File not found: " + file.getPath());
         }
         catch (XmlPullParserException e) {
             loge(e.toString());
@@ -901,13 +922,13 @@
     }
 
     /** Builds a canonical file name for a config file. */
-    private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid,
-                                        int cid) {
+    private String getFilenameForConfig(@NonNull String packageName, @NonNull String extraString,
+                                        @NonNull String iccid, int cid) {
         // the same carrier should have a single copy of XML file named after carrier id.
         // However, it's still possible that platform doesn't recognize the current sim carrier,
         // we will use iccid + carrierid as the canonical file name. carrierid can also handle the
         // cases SIM OTA resolves to different carrier while iccid remains the same.
-        return "carrierconfig-" + packageName + "-" + iccid + "-" + cid + ".xml";
+        return "carrierconfig-" + packageName + extraString + "-" + iccid + "-" + cid + ".xml";
     }
 
     /** Return the current version code of a package, or null if the name is not found. */
@@ -973,6 +994,11 @@
                 retConfig.putAll(config);
                 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
             }
+            config = mPersistentOverrideConfigs[phoneId];
+            if (config != null) {
+                retConfig.putAll(config);
+                retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+            }
             config = mOverrideConfigs[phoneId];
             if (config != null) {
                 retConfig.putAll(config);
@@ -982,7 +1008,8 @@
     }
 
     @Override
-    public void overrideConfig(int subscriptionId, PersistableBundle overrides) {
+    public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides,
+            boolean persistent) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
         //TODO: Also check for SHELL UID to restrict this method to testing only (b/131326259)
@@ -991,18 +1018,38 @@
             log("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
             return;
         }
+        overrideConfig(mOverrideConfigs, phoneId, overrides);
 
-        if (overrides == null) {
-            mOverrideConfigs[phoneId] = new PersistableBundle();
-        } else if (mOverrideConfigs[phoneId] == null) {
-            mOverrideConfigs[phoneId] = overrides;
-        } else {
-            mOverrideConfigs[phoneId].putAll(overrides);
+        if (persistent) {
+            overrideConfig(mPersistentOverrideConfigs, phoneId, overrides);
+
+            if (overrides != null) {
+                final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
+                saveConfigToXml(mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId,
+                        carrierId, mPersistentOverrideConfigs[phoneId]);
+            } else {
+                final String iccid = getIccIdForPhoneId(phoneId);
+                final int cid = getSpecificCarrierIdForPhoneId(phoneId);
+                String fileName = getFilenameForConfig(mPlatformCarrierConfigPackage,
+                        OVERRIDE_PACKAGE_ADDITION, iccid, cid);
+                File fileToDelete = new File(mContext.getFilesDir(), fileName);
+                fileToDelete.delete();
+            }
         }
-
         notifySubscriptionInfoUpdater(phoneId);
     }
 
+    private void overrideConfig(@NonNull PersistableBundle[] currentOverrides, int phoneId,
+            @Nullable PersistableBundle overrides) {
+        if (overrides == null) {
+            currentOverrides[phoneId] = new PersistableBundle();
+        } else if (currentOverrides[phoneId] == null) {
+            currentOverrides[phoneId] = overrides;
+        } else {
+            currentOverrides[phoneId].putAll(overrides);
+        }
+    }
+
     @Override
     public void notifyConfigChangedForSubId(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
@@ -1074,6 +1121,8 @@
             // display ConfigFromCarrierApp
             printConfig(mConfigFromCarrierApp[i], pw, "mConfigFromCarrierApp");
             pw.println("");
+            printConfig(mPersistentOverrideConfigs[i], pw, "mPersistentOverrideConfigs");
+            pw.println("");
             printConfig(mOverrideConfigs[i], pw, "mOverrideConfigs");
         }
 
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index ebadf88..672a27f 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -83,6 +83,11 @@
                 STRING_ARRAY, UNKNOWN
     }
 
+    private class CcOptionParseResult {
+        public int mSubId;
+        public boolean mPersistent;
+    }
+
     // Maps carrier config keys to type. It is possible to infer the type for most carrier config
     // keys by looking at the end of the string which usually tells the type.
     // For instance: "xxxx_string", "xxxx_string_array", etc.
@@ -226,11 +231,12 @@
         pw.println("          is specified, it will choose the default voice SIM slot.");
         pw.println("    KEY: The key to the carrier config value to print. All values are printed");
         pw.println("         if KEY is not specified.");
-        pw.println("  cc set-value [-s SLOT_ID] KEY [NEW_VALUE]");
+        pw.println("  cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
         pw.println("    Set carrier config KEY to NEW_VALUE.");
         pw.println("    Options are:");
         pw.println("      -s: The SIM slot ID to set carrier config value for. If no option");
         pw.println("          is specified, it will choose the default voice SIM slot.");
+        pw.println("      -p: Value will be stored persistent");
         pw.println("    NEW_VALUE specifies the new value for carrier config KEY. Null will be");
         pw.println("      used if NEW_VALUE is not set. Strings should be encapsulated with");
         pw.println("      quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
@@ -568,32 +574,47 @@
         return slotId;
     }
 
-    // Get the subId from argument SLOT_ID if it was provided. Otherwise use the default
-    // subscription.
-    private int getSubIdFromArgumentSlotId(String tag) {
+    // Parse options related to Carrier Config Commands.
+    private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
         PrintWriter errPw = getErrPrintWriter();
-        int subId = SubscriptionManager.getDefaultSubscriptionId();
-        String opt;
+        CcOptionParseResult result = new CcOptionParseResult();
+        result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
+        result.mPersistent = false;
 
+        String opt;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
                 case "-s": {
                     try {
-                        subId = slotStringToSubId(tag, getNextArgRequired());
+                        result.mSubId = slotStringToSubId(tag, getNextArgRequired());
+                        if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
+                            errPw.println(tag + "No valid subscription found.");
+                            return null;
+                        }
+
                     } catch (IllegalArgumentException e) {
                         // Missing slot id
                         errPw.println(tag + "SLOT_ID expected after -s.");
-                        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                        return null;
+                    }
+                    break;
+                }
+                case "-p": {
+                    if (allowOptionPersistent) {
+                        result.mPersistent = true;
+                    } else {
+                        errPw.println(tag + "Unexpected option " + opt);
+                        return null;
                     }
                     break;
                 }
                 default: {
                     errPw.println(tag + "Unknown option " + opt);
-                    return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                    return null;
                 }
             }
         }
-        return subId;
+        return result;
     }
 
     private int slotStringToSubId(String tag, String slotString) {
@@ -657,17 +678,16 @@
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
         String key = null;
 
-        // Get the subId from the SLOT_ID-argument.
-        int subId = getSubIdFromArgumentSlotId(tag);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            errPw.println(tag + "No valid subscription found.");
+        // Parse all options
+        CcOptionParseResult options =  parseCcOptions(tag, false);
+        if (options == null) {
             return -1;
         }
 
         // Get bundle containing all carrier configuration values.
-        PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(subId);
+        PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
         if (bundle == null) {
-            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
             return -1;
         }
 
@@ -698,17 +718,16 @@
         PrintWriter errPw = getErrPrintWriter();
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
 
-        // Get the subId from the SLOT_ID-argument.
-        int subId = getSubIdFromArgumentSlotId(tag);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            errPw.println(tag + "No valid subscription found.");
+        // Parse all options
+        CcOptionParseResult options =  parseCcOptions(tag, true);
+        if (options == null) {
             return -1;
         }
 
         // Get bundle containing all current carrier configuration values.
-        PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(subId);
+        PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
         if (originalValues == null) {
-            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
             return -1;
         }
 
@@ -745,12 +764,12 @@
         }
 
         // Override the value
-        mCarrierConfigManager.overrideConfig(subId, overrideBundle);
+        mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
 
         // Find bundle containing all new carrier configuration values after the override.
-        PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(subId);
+        PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
         if (newValues == null) {
-            errPw.println(tag + "No carrier config values found for subId " + subId + ".");
+            errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
             return -1;
         }
 
@@ -768,15 +787,14 @@
         PrintWriter errPw = getErrPrintWriter();
         String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
 
-        // Get the subId from the SLOT_ID-argument.
-        int subId = getSubIdFromArgumentSlotId(tag);
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            errPw.println(tag + "No valid subscription found.");
+        // Parse all options
+        CcOptionParseResult options =  parseCcOptions(tag, false);
+        if (options == null) {
             return -1;
         }
 
         // Clear all values that has previously been set.
-        mCarrierConfigManager.overrideConfig(subId, null);
+        mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
         getOutPrintWriter()
                 .println("All previously set carrier config override values has been cleared");
         return 0;
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 2051be6..072ae11 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -883,6 +883,7 @@
         if (connection == null) {
             return Connection.createCanceledConnection();
         } else {
+            connection.setTtyEnabled(isTtyModeEnabled(getApplicationContext()));
             return connection;
         }
     }