Allow vCard users to format phone numbers by themselves

Bug: 5348938
Bug: 4177894
Change-Id: Iff9461d8c71c5800b0731c3708867003d75bb395
diff --git a/java/com/android/vcard/VCardBuilder.java b/java/com/android/vcard/VCardBuilder.java
index 969ac1b..bd1e09d 100644
--- a/java/com/android/vcard/VCardBuilder.java
+++ b/java/com/android/vcard/VCardBuilder.java
@@ -818,7 +818,8 @@
         return this;
     }
 
-    public VCardBuilder appendPhones(final List<ContentValues> contentValuesList) {
+    public VCardBuilder appendPhones(final List<ContentValues> contentValuesList,
+            VCardPhoneNumberTranslationCallback translationCallback) {
         boolean phoneLineExists = false;
         if (contentValuesList != null) {
             Set<String> phoneSet = new HashSet<String>();
@@ -836,11 +837,20 @@
                     continue;
                 }
 
-                // PAGER number needs unformatted "phone number".
-                // TODO: It would be better to have this logic as optional.
                 final int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE);
-                if (type == Phone.TYPE_PAGER ||
+                // Note: We prioritize this callback over FLAG_REFRAIN_PHONE_NUMBER_FORMATTING
+                // intentionally. In the future the flag will be replaced by callback
+                // mechanism entirely.
+                if (translationCallback != null) {
+                    phoneNumber = translationCallback.onValueReceived(
+                            phoneNumber, type, label, isPrimary);
+                    if (!phoneSet.contains(phoneNumber)) {
+                        phoneSet.add(phoneNumber);
+                        appendTelLine(type, label, phoneNumber, isPrimary);
+                    }
+                } else if (type == Phone.TYPE_PAGER ||
                         VCardConfig.refrainPhoneNumberFormatting(mVCardType)) {
+                    // Note: PAGER number needs unformatted "phone number".
                     phoneLineExists = true;
                     if (!phoneSet.contains(phoneNumber)) {
                         phoneSet.add(phoneNumber);
diff --git a/java/com/android/vcard/VCardComposer.java b/java/com/android/vcard/VCardComposer.java
index 987e9b5..2f9e8ec 100644
--- a/java/com/android/vcard/VCardComposer.java
+++ b/java/com/android/vcard/VCardComposer.java
@@ -557,6 +557,24 @@
         return buildVCard(contentValuesListMap);
     }
 
+    private VCardPhoneNumberTranslationCallback mPhoneTranslationCallback;
+    /**
+     * <p>
+     * Set a callback for phone number formatting. It will be called every time when this object
+     * receives a phone number for printing.
+     * </p>
+     * <p>
+     * When this is set {@link VCardConfig#FLAG_REFRAIN_PHONE_NUMBER_FORMATTING} will be ignored
+     * and the callback should be responsible for everything about phone number formatting.
+     * </p>
+     * <p>
+     * Caution: This interface will change. Please don't use without any strong reason.
+     * </p>
+     */
+    public void setPhoneNumberTranslationCallback(VCardPhoneNumberTranslationCallback callback) {
+        mPhoneTranslationCallback = callback;
+    }
+
     /**
      * Builds and returns vCard using given map, whose key is CONTENT_ITEM_TYPE defined in
      * {ContactsContract}. Developers can override this method to customize the output.
@@ -569,7 +587,8 @@
             final VCardBuilder builder = new VCardBuilder(mVCardType, mCharset);
             builder.appendNameProperties(contentValuesListMap.get(StructuredName.CONTENT_ITEM_TYPE))
                     .appendNickNames(contentValuesListMap.get(Nickname.CONTENT_ITEM_TYPE))
-                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE))
+                    .appendPhones(contentValuesListMap.get(Phone.CONTENT_ITEM_TYPE),
+                            mPhoneTranslationCallback)
                     .appendEmails(contentValuesListMap.get(Email.CONTENT_ITEM_TYPE))
                     .appendPostals(contentValuesListMap.get(StructuredPostal.CONTENT_ITEM_TYPE))
                     .appendOrganizations(contentValuesListMap.get(Organization.CONTENT_ITEM_TYPE))
diff --git a/java/com/android/vcard/VCardConfig.java b/java/com/android/vcard/VCardConfig.java
index fa1da7b..006241e 100644
--- a/java/com/android/vcard/VCardConfig.java
+++ b/java/com/android/vcard/VCardConfig.java
@@ -231,6 +231,9 @@
      * 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>
+     * <p>
+     * Caution: this flag will be removed in the future, replaced by some richer functionality.
+     * </p>
      */
     public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000;
 
diff --git a/java/com/android/vcard/VCardPhoneNumberTranslationCallback.java b/java/com/android/vcard/VCardPhoneNumberTranslationCallback.java
new file mode 100644
index 0000000..b02f8d1
--- /dev/null
+++ b/java/com/android/vcard/VCardPhoneNumberTranslationCallback.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 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.vcard;
+
+/**
+ * Callback functionality which can be used with
+ * {@link VCardComposer#setPhoneNumberTranslationCallback(VCardPhoneNumberTranslationCallback)}.
+ * See the doc for the method.
+ *
+ * <p>
+ * TODO: this should be more generic
+ * </p>
+ *
+ * @hide This will change
+ */
+public interface VCardPhoneNumberTranslationCallback {
+    /**
+     * Called when a phone number is being handled.
+     * @return formatted phone number.
+     */
+    public String onValueReceived(String rawValue, int type, String label, boolean isPrimary);
+}