diff --git a/res/values/e_arrays.xml b/res/values/e_arrays.xml new file mode 100644 index 0000000000000000000000000000000000000000..a38cce56ce220eb09b4fdd4a9b123da167ba3f12 --- /dev/null +++ b/res/values/e_arrays.xml @@ -0,0 +1,28 @@ + + + + + @string/menu_export_type_vcf_21 + @string/menu_export_type_vcf_30 + @string/menu_export_type_vcf_40 + + + + @string/menu_export_type_vcf_21_value + @string/menu_export_type_vcf_30_value + @string/menu_export_type_vcf_40_value + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 4c2d336f76d5c891fdce00d499af1dcaf91f3299..1d9a49b9c3f3dcc95c212bad393ea1e02a7c032a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1541,4 +1541,13 @@ -Contacts is an open source App for Android Emergency information + + + Export vCard version + VCF 2.1 + VCF 3.0 + VCF 4.0 + v21_generic + v30_generic + v40_generic diff --git a/res/xml/preference_display_options.xml b/res/xml/preference_display_options.xml index 31f2db7e1dc335bb9b5930bf8593cf7f94bd12ff..308ba49426a153461c891d2b5212e697b4cd7b41 100644 --- a/res/xml/preference_display_options.xml +++ b/res/xml/preference_display_options.xml @@ -111,6 +111,14 @@ android:key="export" android:title="@string/menu_export"/> + + sVCardTypeMap = new HashMap<>(); + sVCardTypeMap.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC); + sVCardTypeMap.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC); + sVCardTypeMap.put(VCARD_TYPE_V40_GENERIC_STR, VCARD_TYPE_V40_GENERIC); + + final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences( + mService.getApplicationContext()); + + final String defVcfType = pref.getString(KEY_EXPORT_TYPE, + VCARD_TYPE_V40_GENERIC_STR); + + final int vcardType = sVCardTypeMap.get(defVcfType); composer = new VCardComposer(mService, vcardType, true); diff --git a/src/com/android/contacts/vcard/ImportProcessor.java b/src/com/android/contacts/vcard/ImportProcessor.java index c6fcccb8c2c9f6e63fa3afb6474c57a544774b61..bdeb35312dd7f9e3716d595e8a2013eb6380fe4a 100644 --- a/src/com/android/contacts/vcard/ImportProcessor.java +++ b/src/com/android/contacts/vcard/ImportProcessor.java @@ -30,6 +30,7 @@ import com.android.vcard.VCardInterpreter; import com.android.vcard.VCardParser; import com.android.vcard.VCardParser_V21; import com.android.vcard.VCardParser_V30; +import com.android.vcard.VCardParser_V40; import com.android.vcard.exception.VCardException; import com.android.vcard.exception.VCardNotSupportedException; import com.android.vcard.exception.VCardVersionException; @@ -135,7 +136,8 @@ public class ImportProcessor extends ProcessorBase implements VCardEntryHandler */ possibleVCardVersions = new int[] { ImportVCardActivity.VCARD_VERSION_V21, - ImportVCardActivity.VCARD_VERSION_V30 + ImportVCardActivity.VCARD_VERSION_V30, + ImportVCardActivity.VCARD_VERSION_V40 }; } else { possibleVCardVersions = new int[] { @@ -231,9 +233,10 @@ public class ImportProcessor extends ProcessorBase implements VCardEntryHandler // In the worst case, a user may call cancel() just before creating // mVCardParser. synchronized (this) { - mVCardParser = (vcardVersion == ImportVCardActivity.VCARD_VERSION_V30 ? - new VCardParser_V30(vcardType) : - new VCardParser_V21(vcardType)); + VCardParser useOldVcardParser = (vcardVersion == ImportVCardActivity.VCARD_VERSION_V30 ? + new VCardParser_V30(vcardType) : new VCardParser_V21(vcardType)); + mVCardParser = (vcardVersion == ImportVCardActivity.VCARD_VERSION_V40 ? + new VCardParser_V40(vcardType) : useOldVcardParser); if (isCancelled()) { Log.i(LOG_TAG, "ImportProcessor already recieves cancel request, so " + "send cancel request to vCard parser too."); diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java index b5aa37e35c4208f2bfc81e0e54393173f06336a0..9b91f6be43bb51cda46ad86f4e0a3d4441bf2164 100644 --- a/src/com/android/contacts/vcard/ImportVCardActivity.java +++ b/src/com/android/contacts/vcard/ImportVCardActivity.java @@ -49,6 +49,7 @@ import com.android.vcard.VCardEntryCounter; import com.android.vcard.VCardParser; import com.android.vcard.VCardParser_V21; import com.android.vcard.VCardParser_V30; +import com.android.vcard.VCardParser_V40; import com.android.vcard.VCardSourceDetector; import com.android.vcard.exception.VCardException; import com.android.vcard.exception.VCardNestedException; @@ -83,6 +84,7 @@ public class ImportVCardActivity extends Activity implements ImportVCardDialogFr /* package */ final static int VCARD_VERSION_AUTO_DETECT = 0; /* package */ final static int VCARD_VERSION_V21 = 1; /* package */ final static int VCARD_VERSION_V30 = 2; + /* package */ final static int VCARD_VERSION_V40 = 3; private static final int REQUEST_OPEN_DOCUMENT = 100; @@ -321,12 +323,14 @@ public class ImportVCardActivity extends Activity implements ImportVCardDialogFr int vcardVersion = VCARD_VERSION_V21; try { boolean shouldUseV30 = false; + boolean shouldUseV40 = false; InputStream is; if (data != null) { is = new ByteArrayInputStream(data); } else { is = resolver.openInputStream(localDataUri); } + mVCardParser = new VCardParser_V21(); try { counter = new VCardEntryCounter(); @@ -335,9 +339,11 @@ public class ImportVCardActivity extends Activity implements ImportVCardDialogFr mVCardParser.addInterpreter(detector); mVCardParser.parse(is); } catch (VCardVersionException e1) { + Log.i(LOG_TAG, "Unable to parse as vCard v2.1, trying v3.0"); try { is.close(); } catch (IOException e) { + Log.w(LOG_TAG, "Failed to close InputStream."); } shouldUseV30 = true; @@ -346,6 +352,7 @@ public class ImportVCardActivity extends Activity implements ImportVCardDialogFr } else { is = resolver.openInputStream(localDataUri); } + mVCardParser = new VCardParser_V30(); try { counter = new VCardEntryCounter(); @@ -354,18 +361,43 @@ public class ImportVCardActivity extends Activity implements ImportVCardDialogFr mVCardParser.addInterpreter(detector); mVCardParser.parse(is); } catch (VCardVersionException e2) { - throw new VCardException("vCard with unspported version."); + Log.i(LOG_TAG, "Unable to parse as vCard v3.0, trying v4.0"); + try { + is.close(); + } catch (IOException e) { + Log.w(LOG_TAG, "Failed to close InputStream."); + } + + shouldUseV40 = true; + if (data != null) { + is = new ByteArrayInputStream(data); + } else { + is = resolver.openInputStream(localDataUri); + } + + mVCardParser = new VCardParser_V40(); + try { + counter = new VCardEntryCounter(); + detector = new VCardSourceDetector(); + mVCardParser.addInterpreter(counter); + mVCardParser.addInterpreter(detector); + mVCardParser.parse(is); + } catch (VCardVersionException e3) { + throw new VCardException("vCard with unsupported version."); + } } } finally { if (is != null) { try { is.close(); } catch (IOException e) { + Log.w(LOG_TAG, "Failed to close InputStream."); } } } - vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21; + int useOldVcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21; + vcardVersion = shouldUseV40 ? VCARD_VERSION_V40 : useOldVcardVersion; } catch (VCardNestedException e) { Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive)."); // Go through without throwing the Exception, as we may be able to detect the