Add FLAG_RERAIN_PHONE_NUMBER_FORMATTING.

Sometimes using PhoneNumberUtils takes unexpected side effects.
For example, PAUSE mark (#) is removed and operation on the phone number does
not work well in some devices.
I also concern removing the PhoneNumberUtils logic since some other
mobile phones cannot understand # or alphabets and starts emitting errors
after the modification.

I'll add a flag instead of just removing the code and let users choose it.

Bug: 2329952
Change-Id: I4ffdd01ebb8ac320b8b67a5848a747af13c6ad1a
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
index 0a6415d..1da6d7a 100644
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -642,22 +642,18 @@
                 if (TextUtils.isEmpty(phoneNumber)) {
                     continue;
                 }
-                int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE);
-                if (type == Phone.TYPE_PAGER) {
+
+                // PAGER number needs unformatted "phone number".
+                final int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE);
+                if (type == Phone.TYPE_PAGER ||
+                        VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
                     phoneLineExists = true;
                     if (!phoneSet.contains(phoneNumber)) {
                         phoneSet.add(phoneNumber);
                         appendTelLine(type, label, phoneNumber, isPrimary);
                     }
                 } else {
-                    // The entry "may" have several phone numbers when the contact entry is
-                    // corrupted because of its original source.
-                    //
-                    // e.g. I encountered the entry like the following.
-                    // "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami); ..."
-                    // This kind of entry is not able to be inserted via Android devices, but
-                    // possible if the source of the data is already corrupted.
-                    List<String> phoneNumberList = splitIfSeveralPhoneNumbersExist(phoneNumber);
+                    final List<String> phoneNumberList = splitAndTrimPhoneNumbers(phoneNumber);
                     if (phoneNumberList.isEmpty()) {
                         continue;
                     }
@@ -670,7 +666,7 @@
                             phoneSet.add(actualPhoneNumber);
                             appendTelLine(type, label, formattedPhoneNumber, isPrimary);
                         }
-                    }
+                    }  // for (String actualPhoneNumber : phoneNumberList) {
                 }
             }
         }
@@ -682,15 +678,38 @@
         return this;
     }
 
-    private List<String> splitIfSeveralPhoneNumbersExist(final String phoneNumber) {
-        List<String> phoneList = new ArrayList<String>();
+    /**
+     * <p>
+     * Splits a given string expressing phone numbers into several strings, and remove
+     * unnecessary characters inside them. The size of a returned list becomes 1 when
+     * no split is needed.
+     * </p>
+     * <p>
+     * The given number "may" have several phone numbers when the contact entry is corrupted
+     * because of its original source.
+     * e.g. "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami)"
+     * </p>
+     * <p>
+     * This kind of "phone numbers" will not be created with Android vCard implementation,
+     * but we may encounter them if the source of the input data has already corrupted
+     * implementation.
+     * </p>
+     * <p>
+     * To handle this case, this method first splits its input into multiple parts
+     * (e.g. "111-222-3333 (Miami)", "444-555-6666 (Broward", and 305653-6796 (Miami)") and
+     * removes unnecessary strings like "(Miami)".
+     * </p>
+     * <p>
+     * Do not call this method when trimming is inappropriate for its receivers.
+     * </p>
+     */
+    private List<String> splitAndTrimPhoneNumbers(final String phoneNumber) {
+        final List<String> phoneList = new ArrayList<String>();
 
         StringBuilder builder = new StringBuilder();
         final int length = phoneNumber.length();
         for (int i = 0; i < length; i++) {
             final char ch = phoneNumber.charAt(i);
-            // TODO: add a test case for string with '+', and care the other possible issues
-            // which may happen by ignoring non-digits other than '+'.
             if (Character.isDigit(ch) || ch == '+') {
                 builder.append(ch);
             } else if ((ch == ';' || ch == '\n') && builder.length() > 0) {
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
index 3409be6..8219840 100644
--- a/core/java/android/pim/vcard/VCardConfig.java
+++ b/core/java/android/pim/vcard/VCardConfig.java
@@ -15,6 +15,7 @@
  */
 package android.pim.vcard;
 
+import android.telephony.PhoneNumberUtils;
 import android.util.Log;
 
 import java.util.HashMap;
@@ -190,6 +191,30 @@
      */
     public static final int FLAG_REFRAIN_IMAGE_EXPORT = 0x02000000;
 
+    /**
+     * <P>
+     * The flag indicating the vCard composer does touch nothing toward phone number Strings
+     * but leave it as is.
+     * </P>
+     * <P>
+     * The vCard specifications mention nothing toward phone numbers, while some devices
+     * do (wrongly, but with innevitable reasons).
+     * For example, there's a possibility Japanese mobile phones are expected to have
+     * just numbers, hypens, plus, etc. but not usual alphabets, while US mobile phones
+     * should get such characters. To make exported vCard simple for external parsers,
+     * we have used {@link PhoneNumberUtils#formatNumber(String)} during export, and
+     * removed unnecessary characters inside the number (e.g. "111-222-3333 (Miami)"
+     * becomes "111-222-3333").
+     * Unfortunate side effect of that use was some control characters used in the other
+     * areas may be badly affected by the formatting.
+     * </P>
+     * <P>
+     * This flag disables that formatting, affecting both importer and exporter.
+     * If the user is aware of some side effects due to the implicit formatting, use this flag.
+     * </P>
+     */
+    public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000;
+
     //// The followings are VCard types available from importer/exporter. ////
 
     /**
@@ -431,6 +456,10 @@
         return sJapaneseMobileTypeSet.contains(vcardType);
     }
 
+    /* package */ static boolean refrainPhoneNumberFormatting(final int vcardType) {
+        return ((vcardType & FLAG_REFRAIN_PHONE_NUMBER_FORMATTING) != 0);
+    }
+
     public static boolean needsToConvertPhoneticString(final int vcardType) {
         return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0);
     }
@@ -445,4 +474,4 @@
 
     private VCardConfig() {
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/pim/vcard/VCardEntry.java b/core/java/android/pim/vcard/VCardEntry.java
index 1327770..7c7e9b8 100644
--- a/core/java/android/pim/vcard/VCardEntry.java
+++ b/core/java/android/pim/vcard/VCardEntry.java
@@ -488,7 +488,7 @@
         final StringBuilder builder = new StringBuilder();
         final String trimed = data.trim();
         final String formattedNumber;
-        if (type == Phone.TYPE_PAGER) {
+        if (type == Phone.TYPE_PAGER || VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
             formattedNumber = trimed;
         } else {
             final int length = trimed.length();
@@ -500,8 +500,7 @@
             }
 
             // Use NANP in default when there's no information about locale.
-            final int formattingType = (VCardConfig.isJapaneseDevice(mVCardType) ?
-                    PhoneNumberUtils.FORMAT_JAPAN : PhoneNumberUtils.FORMAT_NANP);
+            final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType);
             formattedNumber = PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
         }
         PhoneData phoneData = new PhoneData(type, formattedNumber, label, isPrimary);
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
index 004a197..2de0464 100644
--- a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
+++ b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java
@@ -275,6 +275,16 @@
         testPhoneBasicCommon(V30);
     }
 
+    public void testPhoneRefrainFormatting() {
+        mVerifier.initForExportTest(V21 | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING);
+        mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.NUMBER, "1234567890(abcdefghijklmnopqrstuvwxyz)")
+                .put(Phone.TYPE, Phone.TYPE_HOME);
+        mVerifier.addPropertyNodesVerifierElemWithEmptyName()
+                .addExpectedNode("TEL", "1234567890(abcdefghijklmnopqrstuvwxyz)",
+                        new TypeSet("HOME"));
+    }
+
     /**
      * Tests that vCard composer emits corresponding type param which we expect.
      */