├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── abhay_yadav.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── Screenshots ├── Screenshot1.png └── Screenshot2.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── aarsy │ │ └── github │ │ └── com │ │ └── ez_vcard_android │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── aarsy │ │ │ └── github │ │ │ └── com │ │ │ └── ez_vcard_android │ │ │ ├── MyAlertDialog.java │ │ │ ├── VCFFiles.java │ │ │ └── VCFfilesListActivity.java │ └── res │ │ ├── drawable-v21 │ │ └── recycler_view_item_background.xml │ │ ├── drawable │ │ └── recycler_view_item_background.xml │ │ ├── layout │ │ ├── activity_vcffiles_list.xml │ │ ├── custom_dialog_layout.xml │ │ └── single_item_vcflist.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── aarsy │ └── github │ └── com │ └── ez_vcard_android │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── vcard-androidParser ├── .gitignore ├── build.gradle └── src └── main ├── AndroidManifest.xml ├── java └── ezvcard │ └── android │ ├── AndroidCustomField.java │ ├── AndroidCustomFieldScribe.java │ ├── ContactOperations.java │ └── DataMappings.java ├── res ├── values-w820dp │ └── dimens.xml └── values │ ├── dimens.xml │ └── strings.xml └── resources └── ez-vcard-android.license /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/abhay_yadav.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Android 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | 1.8 67 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vcard-androidParser 2 | 3 | This is an android library which converts [ez-vcard](http://github.com/mangstadt/ez-vcard) `VCard` object into appropriate Android compatible version so that it can be used to read vcard files easily in android platform 4 | 5 | ------ 6 | 7 | # Download 8 | ### Using Gradle- under dependencies section: 9 | 10 | compile 'com.github.aarsy.vcard-androidParser:vcard-androidParser:1.0.0' 11 | 12 | ### or Using Maven: 13 | 14 | 15 | com.github.aarsy.vcard-androidParser 16 | vcard-androidParser 17 | 1.0.0 18 | pom 19 | 20 | 21 | ------ 22 | 23 | # Documentation 24 | 25 | ### Reading a vcard or vcf file 26 | 27 | File vcardFile = new File(filePath); 28 | VCardReader reader = null; 29 | try { 30 | reader = new VCardReader(vcardFile); 31 | reader.registerScribe(new AndroidCustomFieldScribe()); 32 | 33 | ContactOperations operations = new ContactOperations(context, account_name, account_type); 34 | 35 | //insert contacts with specific account_name and their types. For example: 36 | //both account_name=null and account_type=null if you want to insert contacts into phone 37 | //you can also pass other accounts 38 | 39 | VCard vcard = null; 40 | while ((vcard = reader.readNext()) != null) { 41 | operations.insertContact(vcard); 42 | } 43 | }catch (Exception e) { 44 | e.printStackTrace(); 45 | }finally { 46 | closeQuietly(reader); 47 | } 48 | 49 | See sample for more details.. 50 | 51 | ------ 52 | 53 | # Sample Screenshots
54 | | 55 |
[vcard-androidParser sample app](https://play.google.com/store/apps/details?id=aarsy.gitbub.com.ez_vcard_android) 56 | ------ 57 | 58 | # Compatibility 59 | 60 | **Minimum Android SDK**: This library requires a minimum API level of **10**. 61 | 62 | # Applications already using this library 63 | 64 | [vcfToSIMCard](https://play.google.com/store/apps/details?id=app.aarsy.vcftosimcard) 65 | 66 | # Special thanks to 67 | 68 | [Mike Angstadt](https://github.com/mangstadt) 69 | 70 | -------------------------------------------------------------------------------- /Screenshots/Screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/Screenshots/Screenshot1.png -------------------------------------------------------------------------------- /Screenshots/Screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/Screenshots/Screenshot2.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "aarsy.gitbub.com.ez_vcard_android" 8 | minSdkVersion 13 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.1.0' 28 | compile 'com.android.support:support-v4:25.1.0' 29 | compile 'com.android.support:design:25.1.0' 30 | compile 'com.android.support:recyclerview-v7:25.1.0' 31 | compile 'com.android.support:support-v13:25.1.0' 32 | compile project(':vcard-androidParser') 33 | testCompile 'junit:junit:4.12' 34 | } 35 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/aarsy/github/com/ez_vcard_android/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package aarsy.gitbub.com.ez_vcard_android; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static junit.framework.Assert.assertEquals; 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumentation test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() throws Exception { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("aarsy.gitbub.com.ez_vcard_android", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/aarsy/github/com/ez_vcard_android/MyAlertDialog.java: -------------------------------------------------------------------------------- 1 | package aarsy.github.com.ez_vcard_android; 2 | 3 | import android.graphics.Point; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.DialogFragment; 7 | import android.view.Display; 8 | import android.view.Gravity; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.Window; 13 | import android.view.WindowManager; 14 | import android.widget.LinearLayout; 15 | import android.widget.TextView; 16 | 17 | public class MyAlertDialog extends DialogFragment implements View.OnClickListener { 18 | 19 | private String accountType; 20 | private String accountName; 21 | 22 | public interface ItemAccountSelectedListener { 23 | void onAccountSelected(String account_name, String account_type); 24 | } 25 | 26 | public static MyAlertDialog newInstance(String account_name, String account_type) { 27 | Bundle args = new Bundle(); 28 | MyAlertDialog fragment = new MyAlertDialog(); 29 | args.putString("accountName", account_name); 30 | args.putString("accountType", account_type); 31 | fragment.setArguments(args); 32 | return fragment; 33 | } 34 | 35 | public void onResume() { 36 | // Store access variables for window and blank point 37 | Window window = getDialog().getWindow(); 38 | Point size = new Point(); 39 | // Store dimensions of the screen in `size` 40 | Display display = window.getWindowManager().getDefaultDisplay(); 41 | display.getSize(size); 42 | // Set the width of the dialog proportional to 75% of the screen width 43 | window.setLayout((int) (size.x * 0.85), WindowManager.LayoutParams.WRAP_CONTENT); 44 | window.setGravity(Gravity.CENTER); 45 | // Call super onResume after sizing 46 | super.onResume(); 47 | } 48 | 49 | @Nullable 50 | @Override 51 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 52 | return inflater.inflate(R.layout.custom_dialog_layout, container); 53 | } 54 | 55 | @Override 56 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 57 | super.onViewCreated(view, savedInstanceState); 58 | ((LinearLayout) view.findViewById(R.id.ll_google_account)).setOnClickListener(this); 59 | ((LinearLayout) view.findViewById(R.id.ll_simcard1)).setOnClickListener(this); 60 | ((LinearLayout) view.findViewById(R.id.ll_device)).setOnClickListener(this); 61 | TextView tv_mail_id = (TextView) view.findViewById(R.id.tv_email_id); 62 | accountName = getArguments().getString("accountName"); 63 | accountType = getArguments().getString("accountType"); 64 | tv_mail_id.setText(accountName); 65 | getDialog().setTitle("Save to"); 66 | } 67 | 68 | @Override 69 | public void onClick(View v) { 70 | ItemAccountSelectedListener listener = (ItemAccountSelectedListener) getActivity(); 71 | switch (v.getId()) { 72 | case R.id.ll_google_account: 73 | listener.onAccountSelected(accountName, accountType); 74 | dismiss(); 75 | break; 76 | case R.id.ll_simcard1: 77 | listener.onAccountSelected("SIMCARD", null); 78 | dismiss(); 79 | break; 80 | case R.id.ll_device: 81 | listener.onAccountSelected("Phone", null); 82 | dismiss(); 83 | break; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/aarsy/github/com/ez_vcard_android/VCFFiles.java: -------------------------------------------------------------------------------- 1 | package aarsy.github.com.ez_vcard_android; 2 | 3 | /** 4 | * Created by abhay yadav on 01-Jan-17. 5 | */ 6 | public class VCFFiles { 7 | int fileId; 8 | String fileName; 9 | String filePath; 10 | 11 | public VCFFiles(int file_id, String file_name, String file_fullpath) { 12 | this.fileId=file_id; 13 | this.fileName=file_name; 14 | this.filePath=file_fullpath; 15 | } 16 | 17 | public String getFilePath() { 18 | return filePath; 19 | } 20 | 21 | public void setFilePath(String filePath) { 22 | this.filePath = filePath; 23 | } 24 | 25 | public String getFileName() { 26 | return fileName; 27 | } 28 | 29 | public void setFileName(String fileName) { 30 | this.fileName = fileName; 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/aarsy/github/com/ez_vcard_android/VCFfilesListActivity.java: -------------------------------------------------------------------------------- 1 | package aarsy.github.com.ez_vcard_android; 2 | 3 | import android.Manifest; 4 | import android.accounts.Account; 5 | import android.accounts.AccountManager; 6 | import android.app.Activity; 7 | import android.app.Dialog; 8 | import android.app.ProgressDialog; 9 | import android.content.ContentValues; 10 | import android.content.Context; 11 | import android.content.DialogInterface; 12 | import android.content.OperationApplicationException; 13 | import android.content.pm.PackageManager; 14 | import android.database.Cursor; 15 | import android.net.Uri; 16 | import android.os.AsyncTask; 17 | import android.os.Bundle; 18 | import android.os.RemoteException; 19 | import android.provider.MediaStore; 20 | import android.support.annotation.NonNull; 21 | import android.support.annotation.Nullable; 22 | import android.support.design.widget.Snackbar; 23 | import android.support.v4.app.ActivityCompat; 24 | import android.support.v4.app.FragmentManager; 25 | import android.support.v4.app.LoaderManager; 26 | import android.support.v4.content.ContextCompat; 27 | import android.support.v4.content.CursorLoader; 28 | import android.support.v4.content.Loader; 29 | import android.support.v7.app.ActionBar; 30 | import android.support.v7.app.AlertDialog; 31 | import android.support.v7.app.AppCompatActivity; 32 | import android.support.v7.widget.LinearLayoutManager; 33 | import android.support.v7.widget.RecyclerView; 34 | import android.util.Log; 35 | import android.view.LayoutInflater; 36 | import android.view.View; 37 | import android.view.ViewGroup; 38 | import android.widget.RelativeLayout; 39 | import android.widget.TextView; 40 | import android.widget.Toast; 41 | 42 | import java.io.File; 43 | import java.util.ArrayList; 44 | import java.util.List; 45 | 46 | import ezvcard.VCard; 47 | import ezvcard.android.AndroidCustomFieldScribe; 48 | import ezvcard.android.ContactOperations; 49 | import ezvcard.io.text.VCardReader; 50 | 51 | import static ezvcard.util.IOUtils.closeQuietly; 52 | 53 | 54 | /** 55 | * Created by abhay yadav on 10-Jan-17. 56 | */ 57 | public class VCFfilesListActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks, MyAlertDialog.ItemAccountSelectedListener { 58 | 59 | private static final String TAG = "VCFfilesListActivity"; 60 | private static final int DIALOG_COPY = 1; 61 | private VCFFilesAdapter adapter; 62 | private RecyclerView recyclerView; 63 | private List allFilesList; 64 | private Context context; 65 | private static final int LOADER_ID = 1; 66 | private int selectedFilePositioninList = 0; 67 | private RelativeLayout rlNoContacts; 68 | private final int REQUEST_CODE_PERMISSION_READ_EXT_STORAGE = 100; 69 | private final int REQUEST_CODE_PERMISSION_WRITE_CONTACTS = 101; 70 | private String filePath; 71 | 72 | @Override 73 | protected void onCreate(@Nullable Bundle savedInstanceState) { 74 | super.onCreate(savedInstanceState); 75 | setContentView(R.layout.activity_vcffiles_list); 76 | context = this; 77 | if (savedInstanceState != null) { 78 | filePath = savedInstanceState.getString("filePath"); 79 | } 80 | recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 81 | rlNoContacts = (RelativeLayout) findViewById(R.id.rl_no_contacts_in_list); 82 | ActionBar actionBar = getSupportActionBar(); 83 | actionBar.setLogo(R.mipmap.ic_launcher); 84 | actionBar.setDisplayUseLogoEnabled(true); 85 | actionBar.setDisplayShowHomeEnabled(true); 86 | askPermissionAndFindFiles(Manifest.permission.READ_EXTERNAL_STORAGE, REQUEST_CODE_PERMISSION_READ_EXT_STORAGE, getString(R.string.you_need_to_allow_access_to_ext_storage)); 87 | } 88 | 89 | @Override 90 | protected void onSaveInstanceState(Bundle outState) { 91 | outState.putString("filePath", filePath); 92 | } 93 | 94 | 95 | @Override 96 | protected void onStart() { 97 | super.onStart(); 98 | } 99 | 100 | 101 | 102 | @Override 103 | protected void onResume() { 104 | super.onResume(); 105 | } 106 | 107 | private void askPermissionAndFindFiles(final String permissionType, final int permissionCode, String message) { 108 | int hasExternalStoragePermission = ContextCompat.checkSelfPermission(context, permissionType); 109 | if (hasExternalStoragePermission != PackageManager.PERMISSION_GRANTED) { 110 | if (!ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, permissionType)) { 111 | showMessageOkCancel(message, new DialogInterface.OnClickListener() { 112 | @Override 113 | public void onClick(DialogInterface dialog, int which) { 114 | ActivityCompat.requestPermissions((Activity) context, new String[]{permissionType}, permissionCode); 115 | } 116 | }); 117 | return; 118 | } 119 | ActivityCompat.requestPermissions((Activity) context, new String[]{permissionType}, permissionCode); 120 | return; 121 | } 122 | if (permissionCode == REQUEST_CODE_PERMISSION_READ_EXT_STORAGE) 123 | getSupportLoaderManager().initLoader(LOADER_ID, null, this); 124 | else 125 | //for writing contacts 126 | getAccountsAndShowDialog(); 127 | } 128 | 129 | 130 | private void showMessageOkCancel(String message, DialogInterface.OnClickListener listener) { 131 | new AlertDialog.Builder(context) 132 | .setMessage(message) 133 | .setPositiveButton("Ok", listener) 134 | .setNegativeButton("Cancel", null) 135 | .create() 136 | .show(); 137 | } 138 | 139 | @Override 140 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 141 | switch (requestCode) { 142 | case REQUEST_CODE_PERMISSION_READ_EXT_STORAGE: 143 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 144 | getSupportLoaderManager().initLoader(LOADER_ID, null, this); 145 | } else { 146 | Toast.makeText(context, "Permission denied", Toast.LENGTH_SHORT).show(); 147 | } 148 | break; 149 | case REQUEST_CODE_PERMISSION_WRITE_CONTACTS: 150 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 151 | 152 | } else { 153 | Toast.makeText(context, "Permission denied", Toast.LENGTH_SHORT).show(); 154 | } 155 | break; 156 | 157 | default: 158 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 159 | } 160 | } 161 | 162 | 163 | private void getAccountsAndShowDialog() { 164 | AccountManager am = AccountManager.get(this); 165 | 166 | //Since write contacts permission is already asked and GET_ACCOUNTS permission also lies 167 | // in same permission group therefore there is no need to ask for it. It will be allowed automatically. 168 | if (ActivityCompat.checkSelfPermission(this, Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) { 169 | // TODO: Consider calling 170 | // ActivityCompat#requestPermissions 171 | // here to request the missing permissions, and then overriding 172 | // public void onRequestPermissionsResult(int requestCode, String[] permissions, 173 | // int[] grantResults) 174 | // to handle the case where the user grants the permission. See the documentation 175 | // for ActivityCompat#requestPermissions for more details. 176 | return; 177 | } 178 | Account[] accounts = am.getAccounts(); 179 | String account_name = null; 180 | String account_type = null; 181 | for (Account ac : accounts) { 182 | String acname = ac.name; 183 | String actype = ac.type; 184 | System.out.println("Accounts : " + acname + ", " + actype); 185 | //get the google account 186 | if (actype.equals("com.google")) { 187 | account_name = acname; 188 | account_type = actype; 189 | } 190 | } 191 | FragmentManager fragmentm = getSupportFragmentManager(); 192 | MyAlertDialog dialog = MyAlertDialog.newInstance(account_name, account_type); 193 | dialog.show(fragmentm, "fragment_select"); 194 | } 195 | 196 | 197 | @Override 198 | public Loader onCreateLoader(int id, Bundle args) { 199 | allFilesList = new ArrayList<>(); 200 | if (id == LOADER_ID) { 201 | Uri URI = MediaStore.Files.getContentUri("external"); 202 | //get all files from external storage(both phones memory and SD card's memory) that ends with .vcf extension 203 | String selection = MediaStore.Files.FileColumns.DATA + " like '%.vcf' or " + MediaStore.Files.FileColumns.DATA + " like '&.VCF'"; 204 | return new CursorLoader(this, URI, null, selection, null, MediaStore.Images.ImageColumns.DATE_MODIFIED); 205 | } 206 | return null; 207 | } 208 | 209 | @Override 210 | public void onLoadFinished(Loader loader, Cursor cursor) { 211 | // progressDialog.dismiss(); 212 | if (cursor != null) { 213 | Log.d("cursorcount", " " + cursor.getCount() + " " + cursor.getColumnCount()); 214 | if (cursor.moveToFirst()) { 215 | do { 216 | String file_name = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME)); 217 | int file_id = cursor.getInt(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID)); 218 | String file_fullpath = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); 219 | if (file_name == null) 220 | file_name = file_fullpath.substring(file_fullpath.lastIndexOf('/') + 1); 221 | VCFFiles vcfFiles = new VCFFiles(file_id, file_name, file_fullpath); 222 | allFilesList.add(vcfFiles); 223 | System.out.println("namessss: " + file_name + " " + file_id + " " + file_fullpath); 224 | } while (cursor.moveToNext()); 225 | 226 | } 227 | if (!allFilesList.isEmpty()) { 228 | recyclerView.setVisibility(View.VISIBLE); 229 | rlNoContacts.setVisibility(View.GONE); 230 | adapter = new VCFFilesAdapter(context); 231 | Log.d("vcffilelistSize", " " + allFilesList.size()); 232 | RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context); 233 | recyclerView.setLayoutManager(mLayoutManager); 234 | recyclerView.setAdapter(adapter); 235 | } 236 | } 237 | } 238 | 239 | @Override 240 | public void onLoaderReset(Loader loader) { 241 | } 242 | 243 | 244 | public void readVCFAndWrite(Context context, String path, String acc_name, String acc_type) { 245 | 246 | 247 | //Log.d("insertToPhoneclick", "true "+path+" "+acc_name+" "+acc_type); 248 | File vcardFile = new File(path); 249 | if (!vcardFile.exists()) { 250 | throw new RuntimeException("vCard file does not exist: " + path); 251 | } 252 | VCardReader reader = null; 253 | try { 254 | reader = new VCardReader(vcardFile); 255 | reader.registerScribe(new AndroidCustomFieldScribe()); 256 | ContactOperations operations = new ContactOperations(getApplicationContext(), acc_name, acc_type); 257 | VCard vcard = null; 258 | while ((vcard = reader.readNext()) != null) { 259 | //inserts contacts automatically 260 | operations.insertContact(vcard); 261 | } 262 | } catch (Exception e) { 263 | e.printStackTrace(); 264 | } finally { 265 | closeQuietly(reader); 266 | } 267 | } 268 | 269 | 270 | public void readVCFAndWriteToSimCard(Context context, String path, String acc_name, String acc_type) { 271 | 272 | Log.d("insertTosimclick", "true "+path); 273 | //1).inserting into sim card using the basic approach. 274 | 275 | //2).You can also use same method which is used while inserting into phone or gmail account if and only if there exists an SIM card 276 | // accounts in while getting all acounts like we have done for getting gmail account 277 | File vcardFile = new File(path); 278 | Uri simUri = Uri.parse("content://icc/adn"); 279 | ContentValues cv = new ContentValues(); 280 | if (!vcardFile.exists()) { 281 | throw new RuntimeException("vCard file does not exist: " + path); 282 | } 283 | VCardReader reader = null; 284 | try { 285 | reader = new VCardReader(vcardFile); 286 | reader.registerScribe(new AndroidCustomFieldScribe()); 287 | VCard vcard = null; 288 | while ((vcard = reader.readNext()) != null) { 289 | //I'm inserting only one contact here 290 | try { 291 | if (vcard.getFormattedName().getValue() != null && !vcard.getTelephoneNumbers().isEmpty()) { 292 | cv = new ContentValues(); 293 | cv.put("tag", vcard.getFormattedName().getValue()); 294 | cv.put("number", vcard.getTelephoneNumbers().get(0).getText()); 295 | getContentResolver().insert(simUri, cv); 296 | } 297 | }catch(Exception e) { 298 | e.printStackTrace(); 299 | } 300 | } 301 | } catch (Exception e) { 302 | e.printStackTrace(); 303 | } finally { 304 | closeQuietly(reader); 305 | } 306 | } 307 | 308 | @Override 309 | protected void onStop() { 310 | super.onStop(); 311 | try { 312 | getSupportLoaderManager().destroyLoader(LOADER_ID); 313 | } catch (Exception e) { 314 | e.printStackTrace(); 315 | } 316 | } 317 | 318 | @Override 319 | public void onAccountSelected(String account_name, String account_type) { 320 | SaveContacts saveContacts; 321 | if (account_name.equals("SIMCARD")) { 322 | saveContacts = new SaveContacts(); 323 | saveContacts.execute(null, null, true); 324 | } else if (account_name.equals("Phone")) { 325 | saveContacts = new SaveContacts(); 326 | //account_name and account_type are null for phone 327 | saveContacts.execute(null, null, false); 328 | } else { 329 | saveContacts = new SaveContacts(); 330 | //google account_name and account_type fetched before 331 | saveContacts.execute(account_name, account_type, false); 332 | } 333 | } 334 | 335 | 336 | ProgressDialog progressDialog; 337 | 338 | 339 | private class SaveContacts extends AsyncTask { 340 | 341 | 342 | @Override 343 | protected void onPreExecute() { 344 | super.onPreExecute(); 345 | progressDialog = ProgressDialog.show(context, "", "Saving contacts"); 346 | 347 | } 348 | 349 | public void doProgress(int progress) { 350 | Log.d("prrrogress", " " + progress); 351 | publishProgress(progress); 352 | } 353 | 354 | 355 | @Override 356 | protected void onProgressUpdate(Integer... values) { 357 | //super.onProgressUpdate(values); 358 | Log.d("progressValues ", " " + values[0]); 359 | progressDialog.setProgress((int) values[0]); 360 | } 361 | 362 | @Override 363 | protected Void doInBackground(Object... params) { 364 | String accname = (String) params[0]; 365 | String acctype = (String) params[1]; 366 | boolean savetosim = (boolean) params[2]; 367 | if (savetosim) 368 | insertToSimCard(selectedFilePositioninList); 369 | else 370 | insertToPhoneOrGmailAccount(accname, acctype, selectedFilePositioninList); 371 | return null; 372 | } 373 | 374 | @Override 375 | protected void onPostExecute(Void aVoid) { 376 | super.onPostExecute(aVoid); 377 | progressDialog.dismiss(); 378 | Toast.makeText(context, "Contacts Inserted", Toast.LENGTH_SHORT).show(); 379 | } 380 | } 381 | 382 | private void insertToPhoneOrGmailAccount(String account_name, String account_type, int position) { 383 | readVCFAndWrite(context, allFilesList.get(position).getFilePath(), account_name, account_type); 384 | 385 | } 386 | 387 | 388 | 389 | private void insertToSimCard(int position) { 390 | 391 | readVCFAndWriteToSimCard(context, allFilesList.get(position).getFilePath(), null, null); 392 | } 393 | 394 | 395 | private class MyViewHolder extends RecyclerView.ViewHolder 396 | implements View.OnClickListener { 397 | TextView fileName, path, serialNo; 398 | VCFFiles data; 399 | 400 | public MyViewHolder(View view) { 401 | super(view); 402 | fileName = (TextView) view.findViewById(R.id.file_name); 403 | path = (TextView) view.findViewById(R.id.file_path); 404 | serialNo = (TextView) view.findViewById(R.id.serial); 405 | view.setOnClickListener(this); 406 | } 407 | 408 | public void bindUser(VCFFiles data, int position) { 409 | this.data = data; 410 | fileName.setText(data.getFileName()); 411 | path.setText(data.getFilePath()); 412 | serialNo.setText((position + 1) + "."); 413 | } 414 | 415 | @Override 416 | public void onClick(View v) { 417 | filePath = data.getFilePath(); 418 | selectedFilePositioninList = this.getAdapterPosition(); 419 | askPermissionAndFindFiles(Manifest.permission.WRITE_CONTACTS, REQUEST_CODE_PERMISSION_WRITE_CONTACTS, getString(R.string.allow_access_to_write_contacts)); 420 | } 421 | 422 | 423 | } 424 | 425 | private class VCFFilesAdapter extends RecyclerView.Adapter { 426 | Context context; 427 | 428 | public VCFFilesAdapter(Context context) { 429 | this.context = context; 430 | } 431 | 432 | @Override 433 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 434 | View itemView = LayoutInflater.from(parent.getContext()) 435 | .inflate(R.layout.single_item_vcflist, parent, false); 436 | return new MyViewHolder(itemView); 437 | } 438 | 439 | @Override 440 | public void onBindViewHolder(MyViewHolder holder, int position) { 441 | final VCFFiles data = allFilesList.get(position); 442 | holder.bindUser(data, position); 443 | } 444 | 445 | @Override 446 | public int getItemCount() { 447 | return allFilesList.size(); 448 | } 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/recycler_view_item_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/recycler_view_item_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_vcffiles_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 18 | 24 | 25 | 30 | 31 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/custom_dialog_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 26 | 27 | 28 | 35 | 36 | 37 | 45 | 46 | 47 | 48 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/res/layout/single_item_vcflist.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 25 | 26 | 34 | 35 | 43 | 44 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #ffffff 7 | #21000000 8 | #00000000 9 | #000000 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | EZ-Vcard-Android 3 | Select a backup file 4 | No vcf (contact\'s backup) file currently present in your device. 5 | File name 6 | File path 7 | Allow access to external storage 8 | Email address 9 | Google account 10 | Device 11 | SIM card 12 | You need to allow access to write contacts 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/test/java/aarsy/github/com/ez_vcard_android/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package aarsy.gitbub.com.ez_vcard_android; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' 11 | 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aarsy/vcard-androidParser/6a417126770a6b51b6ec921c56aac6916c023d39/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':vcard-androidParser' 2 | -------------------------------------------------------------------------------- /vcard-androidParser/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /vcard-androidParser/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.jfrog.bintray' 3 | apply plugin: 'com.github.dcendents.android-maven' 4 | 5 | ext { 6 | bintrayRepo = 'maven' 7 | bintrayName = 'vcard-androidParser' 8 | 9 | publishedGroupId = 'com.github.aarsy.vcard-androidParser' 10 | libraryName = 'vcard-androidParser' 11 | artifact = 'vcard-androidParser' 12 | 13 | libraryDescription = '"vcard-androidParser" is an android library for developers who need to process contacts backup files or simple vcard or vcf files. This library is android mapping of ez-vcard' 14 | 15 | siteUrl = 'https://github.com/aarsy/vcard-androidParser' 16 | gitUrl = 'https://github.com/aarsy/vcard-androidParser.git' 17 | 18 | libraryVersion = '1.0.0' 19 | 20 | developerId = 'aarsy' 21 | developerName = 'Abhay Raj Singh Yadav' 22 | developerEmail = 'abhayyadavleo@gmail.com ' 23 | 24 | licenseName = 'The Apache Software License, Version 2.0' 25 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 26 | allLicenses = ["Apache-2.0", "BSD-3-Clause"] 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | android { 34 | compileSdkVersion 25 35 | buildToolsVersion "25.0.2" 36 | 37 | defaultConfig { 38 | minSdkVersion 10 39 | targetSdkVersion 25 40 | versionCode 1 41 | versionName "1.0.0" 42 | } 43 | buildTypes { 44 | release { 45 | minifyEnabled false 46 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 47 | } 48 | } 49 | } 50 | 51 | 52 | dependencies { 53 | compile('com.googlecode.ez-vcard:ez-vcard:0.10.1') { 54 | exclude group: 'org.jsoup' 55 | exclude group: 'org.freemarker' 56 | exclude group: 'com.fasterxml.jackson.core' 57 | } 58 | compile fileTree(dir: 'libs', include: ['*.jar']) 59 | } 60 | 61 | group = publishedGroupId // Maven Group ID for the artifact 62 | 63 | 64 | install { 65 | repositories.mavenInstaller { 66 | // This generates POM.xml with proper parameters 67 | pom { 68 | project { 69 | packaging 'aar' 70 | groupId publishedGroupId 71 | artifactId artifact 72 | 73 | // Add your description here 74 | name libraryName 75 | description libraryDescription 76 | url siteUrl 77 | 78 | // Set your license 79 | licenses { 80 | license { 81 | name licenseName 82 | url licenseUrl 83 | } 84 | } 85 | developers { 86 | developer { 87 | id developerId 88 | name developerName 89 | email developerEmail 90 | } 91 | } 92 | scm { 93 | connection gitUrl 94 | developerConnection gitUrl 95 | url siteUrl 96 | 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | 104 | version = libraryVersion 105 | 106 | if (project.hasProperty("android")) { // Android libraries 107 | task sourcesJar(type: Jar) { 108 | classifier = 'sources' 109 | from android.sourceSets.main.java.srcDirs 110 | } 111 | 112 | task javadoc(type: Javadoc) { 113 | source = android.sourceSets.main.java.srcDirs 114 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 115 | } 116 | afterEvaluate { 117 | javadoc.classpath += files(android.libraryVariants.collect { variant -> 118 | variant.javaCompile.classpath.files 119 | }) 120 | } 121 | } else { // Java libraries 122 | task sourcesJar(type: Jar, dependsOn: classes) { 123 | classifier = 'sources' 124 | from sourceSets.main.allSource 125 | } 126 | } 127 | 128 | task javadocJar(type: Jar, dependsOn: javadoc) { 129 | classifier = 'javadoc' 130 | from javadoc.destinationDir 131 | } 132 | 133 | artifacts { 134 | archives javadocJar 135 | archives sourcesJar 136 | } 137 | 138 | // Bintray 139 | Properties properties = new Properties() 140 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 141 | 142 | bintray { 143 | user = properties.getProperty("bintray.user") 144 | key = properties.getProperty("bintray.apikey") 145 | 146 | configurations = ['archives'] 147 | pkg { 148 | repo = bintrayRepo 149 | name = bintrayName 150 | desc = libraryDescription 151 | websiteUrl = siteUrl 152 | vcsUrl = gitUrl 153 | licenses = allLicenses 154 | publish = true 155 | publicDownloadNumbers = true 156 | version { 157 | desc = libraryDescription 158 | gpg { 159 | sign = true //Determines whether to GPG sign the files. The default is false 160 | passphrase = properties.getProperty("bintray.gpg.password") 161 | //Optional. The passphrase for GPG signing' 162 | } 163 | } 164 | } 165 | } -------------------------------------------------------------------------------- /vcard-androidParser/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/java/ezvcard/android/AndroidCustomField.java: -------------------------------------------------------------------------------- 1 | package ezvcard.android; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import ezvcard.VCard; 8 | import ezvcard.VCardVersion; 9 | import ezvcard.Warning; 10 | import ezvcard.property.VCardProperty; 11 | 12 | /* 13 | Copyright (c) 2014-2015, Michael Angstadt 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright notice, this 20 | list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright notice, 22 | this list of conditions and the following disclaimer in the documentation 23 | and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 29 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 32 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | 36 | The views and conclusions contained in the software and documentation are those 37 | of the authors and should not be interpreted as representing official policies, 38 | either expressed or implied, of the FreeBSD Project. 39 | */ 40 | 41 | /** 42 | * Represents an "X-ANDROID-CUSTOM" property. 43 | * @author Michael Angstadt 44 | */ 45 | public class AndroidCustomField extends VCardProperty { 46 | private String type; 47 | private boolean dir; 48 | private List values = new ArrayList(); 49 | 50 | /** 51 | * Creates an "item" field. 52 | * @param type the type 53 | * @param value the value 54 | * @return the property 55 | */ 56 | public static AndroidCustomField item(String type, String value) { 57 | AndroidCustomField property = new AndroidCustomField(); 58 | property.dir = false; 59 | property.type = type; 60 | property.values.add(value); 61 | return property; 62 | } 63 | 64 | /** 65 | * Creates a "dir" field. 66 | * @param type the type 67 | * @param values the values 68 | * @return the property 69 | */ 70 | public static AndroidCustomField dir(String type, String... values) { 71 | AndroidCustomField property = new AndroidCustomField(); 72 | property.dir = true; 73 | property.type = type; 74 | Collections.addAll(property.values, values); 75 | return property; 76 | } 77 | 78 | public String getType() { 79 | return type; 80 | } 81 | 82 | public void setType(String type) { 83 | this.type = type; 84 | } 85 | 86 | public List getValues() { 87 | return values; 88 | } 89 | 90 | public boolean isDir() { 91 | return dir; 92 | } 93 | 94 | public void setDir(boolean dir) { 95 | this.dir = dir; 96 | } 97 | 98 | public boolean isItem() { 99 | return !isDir(); 100 | } 101 | 102 | public void setItem(boolean item) { 103 | setDir(!item); 104 | } 105 | 106 | public boolean isNickname() { 107 | return "nickname".equals(type); 108 | } 109 | 110 | public boolean isContactEvent() { 111 | return "contact_event".equals(type); 112 | } 113 | 114 | public boolean isRelation() { 115 | return "relation".equals(type); 116 | } 117 | 118 | @Override 119 | protected void _validate(List warnings, VCardVersion version, VCard vcard){ 120 | if (type == null){ 121 | warnings.add(new Warning("No type specified.")); 122 | } 123 | if (isItem() && values.size() != 1){ 124 | warnings.add(new Warning("Items must contain exactly one value.")); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/java/ezvcard/android/AndroidCustomFieldScribe.java: -------------------------------------------------------------------------------- 1 | package ezvcard.android; 2 | 3 | import com.github.mangstadt.vinnie.io.VObjectPropertyValues; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import ezvcard.VCardDataType; 11 | import ezvcard.VCardVersion; 12 | import ezvcard.io.SkipMeException; 13 | import ezvcard.io.scribe.VCardPropertyScribe; 14 | import ezvcard.io.text.WriteContext; 15 | import ezvcard.parameter.VCardParameters; 16 | 17 | /* 18 | Copyright (c) 2014-2015, Michael Angstadt 19 | All rights reserved. 20 | 21 | Redistribution and use in source and binary forms, with or without 22 | modification, are permitted provided that the following conditions are met: 23 | 24 | 1. Redistributions of source code must retain the above copyright notice, this 25 | list of conditions and the following disclaimer. 26 | 2. Redistributions in binary form must reproduce the above copyright notice, 27 | this list of conditions and the following disclaimer in the documentation 28 | and/or other materials provided with the distribution. 29 | 30 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 31 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 33 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 34 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 35 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 37 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | The views and conclusions contained in the software and documentation are those 42 | of the authors and should not be interpreted as representing official policies, 43 | either expressed or implied, of the FreeBSD Project. 44 | */ 45 | 46 | /** 47 | * Marshals {@link AndroidCustomField} properties. 48 | * @author Michael Angstadt 49 | */ 50 | public class AndroidCustomFieldScribe extends VCardPropertyScribe { 51 | private final Pattern uriRegex = Pattern.compile("^vnd\\.android\\.cursor\\.(dir|item)/(.*)"); 52 | 53 | public AndroidCustomFieldScribe() { 54 | super(AndroidCustomField.class, "X-ANDROID-CUSTOM"); 55 | } 56 | 57 | @Override 58 | protected VCardDataType _defaultDataType(VCardVersion version) { 59 | return null; 60 | } 61 | 62 | @Override 63 | protected String _writeText(AndroidCustomField property, WriteContext context) { 64 | String type = property.getType(); 65 | List values = property.getValues(); 66 | 67 | List out = new ArrayList(); 68 | String uri = "vnd.android.cursor." + (property.isDir() ? "dir" : "item") + "/" + (type == null ? "" : type); 69 | out.add(uri); 70 | if (property.isItem()) { 71 | out.add(values.isEmpty() ? "" : values.get(0)); 72 | } else { 73 | out.addAll(values); 74 | } 75 | return VObjectPropertyValues.writeList(out); 76 | } 77 | 78 | 79 | @Override 80 | protected AndroidCustomField _parseText(String value, VCardDataType dataType, VCardVersion version, VCardParameters parameters, List warnings) { 81 | VObjectPropertyValues.SemiStructuredValueIterator it = new VObjectPropertyValues.SemiStructuredValueIterator(value); 82 | 83 | String uri = it.next(); 84 | if (uri == null){ 85 | throw new SkipMeException("Property value is blank."); 86 | } 87 | 88 | Matcher matcher = uriRegex.matcher(uri); 89 | if (!matcher.find()){ 90 | throw new SkipMeException("Property URI is invalid: " + uri); 91 | } 92 | 93 | AndroidCustomField property = new AndroidCustomField(); 94 | property.setDir(matcher.group(1).equals("dir")); 95 | property.setType(matcher.group(2)); 96 | while (it.hasNext()) { 97 | property.getValues().add(it.next()); 98 | } 99 | return property; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/java/ezvcard/android/ContactOperations.java: -------------------------------------------------------------------------------- 1 | package ezvcard.android; 2 | 3 | import static android.text.TextUtils.isEmpty; 4 | 5 | import java.text.DateFormat; 6 | import java.text.SimpleDateFormat; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import android.annotation.TargetApi; 14 | import android.content.ContentProviderOperation; 15 | import android.content.ContentValues; 16 | import android.content.Context; 17 | import android.content.OperationApplicationException; 18 | import android.os.Build; 19 | import android.os.RemoteException; 20 | import android.provider.ContactsContract; 21 | import ezvcard.VCard; 22 | import ezvcard.property.Address; 23 | import ezvcard.property.Birthday; 24 | import ezvcard.property.Email; 25 | import ezvcard.property.FormattedName; 26 | import ezvcard.property.Impp; 27 | import ezvcard.property.Nickname; 28 | import ezvcard.property.Note; 29 | import ezvcard.property.Organization; 30 | import ezvcard.property.Photo; 31 | import ezvcard.property.RawProperty; 32 | import ezvcard.property.StructuredName; 33 | import ezvcard.property.Telephone; 34 | import ezvcard.property.Title; 35 | import ezvcard.property.Url; 36 | import ezvcard.property.VCardProperty; 37 | import ezvcard.util.TelUri; 38 | 39 | /* 40 | Copyright (c) 2014-2015, Michael Angstadt 41 | All rights reserved. 42 | 43 | Redistribution and use in source and binary forms, with or without 44 | modification, are permitted provided that the following conditions are met: 45 | 46 | 1. Redistributions of source code must retain the above copyright notice, this 47 | list of conditions and the following disclaimer. 48 | 2. Redistributions in binary form must reproduce the above copyright notice, 49 | this list of conditions and the following disclaimer in the documentation 50 | and/or other materials provided with the distribution. 51 | 52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 53 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 54 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 55 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 56 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 57 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 58 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 59 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 61 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 | 63 | The views and conclusions contained in the software and documentation are those 64 | of the authors and should not be interpreted as representing official policies, 65 | either expressed or implied, of the FreeBSD Project. 66 | */ 67 | 68 | /** 69 | * Inserts a {@link VCard} into an Android database. 70 | * 71 | * @author Pratyush 72 | * @author Michael Angstadt 73 | */ 74 | public class ContactOperations { 75 | private static final int rawContactID = 0; 76 | 77 | private final Context context; 78 | private final NonEmptyContentValues account; 79 | 80 | 81 | //using this constructor contacts be inserted in phone memory 82 | public ContactOperations(Context context) { 83 | this(context, null, null); 84 | } 85 | 86 | public ContactOperations(Context context, String accountName, String accountType) { 87 | this.context = context; 88 | 89 | account = new NonEmptyContentValues(); 90 | account.put(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType); 91 | account.put(ContactsContract.RawContacts.ACCOUNT_NAME, accountName); 92 | } 93 | 94 | public void insertContact(VCard vcard) throws RemoteException, OperationApplicationException { 95 | // TODO handle Raw properties - Raw properties include various extension which start with "X-" like X-ASSISTANT, X-AIM, X-SPOUSE 96 | 97 | List contentValues = new ArrayList(); 98 | convertName(contentValues, vcard); 99 | convertNickname(contentValues, vcard); 100 | convertPhones(contentValues, vcard); 101 | convertEmails(contentValues, vcard); 102 | convertAddresses(contentValues, vcard); 103 | convertIms(contentValues, vcard); 104 | 105 | // handle Android Custom fields..This is only valid for Android generated Vcards. As the Android would 106 | // generate NickName, ContactEvents other than Birthday and RelationShip with this "X-ANDROID-CUSTOM" name 107 | convertCustomFields(contentValues, vcard); 108 | 109 | // handle Iphone kinda of group properties. which are grouped together. 110 | convertGroupedProperties(contentValues, vcard); 111 | 112 | convertBirthdays(contentValues, vcard); 113 | 114 | convertWebsites(contentValues, vcard); 115 | convertNotes(contentValues, vcard); 116 | convertPhotos(contentValues, vcard); 117 | convertOrganization(contentValues, vcard); 118 | 119 | ArrayList operations = new ArrayList(contentValues.size()); 120 | ContentValues cv = account.getContentValues(); 121 | //ContactsContract.RawContact.CONTENT_URI needed to add account, backReference is also not needed 122 | ContentProviderOperation operation = 123 | ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) 124 | .withValues(cv) 125 | .build(); 126 | operations.add(operation); 127 | for (NonEmptyContentValues values : contentValues) { 128 | cv = values.getContentValues(); 129 | if (cv.size() == 0) { 130 | continue; 131 | } 132 | 133 | //@formatter:off 134 | operation = 135 | ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) 136 | .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactID) 137 | .withValues(cv) 138 | .build(); 139 | //@formatter:on 140 | operations.add(operation); 141 | } 142 | 143 | // Executing all the insert operations as a single database transaction 144 | context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations); 145 | } 146 | 147 | private void convertName(List contentValues, VCard vcard) { 148 | NonEmptyContentValues values = new NonEmptyContentValues(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); 149 | 150 | String firstName = null, lastName = null, namePrefix = null, nameSuffix = null; 151 | StructuredName n = vcard.getStructuredName(); 152 | if (n != null) { 153 | firstName = n.getGiven(); 154 | values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName); 155 | 156 | lastName = n.getFamily(); 157 | values.put(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, lastName); 158 | 159 | List prefixes = n.getPrefixes(); 160 | if (!prefixes.isEmpty()) { 161 | namePrefix = prefixes.get(0); 162 | values.put(ContactsContract.CommonDataKinds.StructuredName.PREFIX, namePrefix); 163 | } 164 | 165 | List suffixes = n.getSuffixes(); 166 | if (!suffixes.isEmpty()) { 167 | nameSuffix = suffixes.get(0); 168 | values.put(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, nameSuffix); 169 | } 170 | } 171 | 172 | FormattedName fn = vcard.getFormattedName(); 173 | String formattedName = (fn == null) ? null : fn.getValue(); 174 | 175 | String displayName; 176 | if (isEmpty(formattedName)) { 177 | StringBuilder sb = new StringBuilder(); 178 | if (!isEmpty(namePrefix)){ 179 | sb.append(namePrefix).append(' '); 180 | } 181 | if (!isEmpty(firstName)){ 182 | sb.append(firstName).append(' '); 183 | } 184 | if (!isEmpty(lastName)){ 185 | sb.append(lastName).append(' '); 186 | } 187 | if (!isEmpty(nameSuffix)){ 188 | if (sb.length() > 0){ 189 | sb.deleteCharAt(sb.length()-1); //delete space character 190 | sb.append(", "); 191 | } 192 | sb.append(nameSuffix); 193 | } 194 | 195 | displayName = sb.toString().trim(); 196 | } else { 197 | displayName = formattedName; 198 | } 199 | values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName); 200 | 201 | RawProperty xPhoneticFirstName = vcard.getExtendedProperty("X-PHONETIC-FIRST-NAME"); 202 | String firstPhoneticName = (xPhoneticFirstName == null) ? null : xPhoneticFirstName.getValue(); 203 | values.put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME, firstPhoneticName); 204 | 205 | RawProperty xPhoneticLastName = vcard.getExtendedProperty("X-PHONETIC-LAST-NAME"); 206 | String lastPhoneticName = (xPhoneticLastName == null) ? null : xPhoneticLastName.getValue(); 207 | values.put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME, lastPhoneticName); 208 | 209 | contentValues.add(values); 210 | } 211 | 212 | private void convertNickname(List contentValues, VCard vcard) { 213 | for (Nickname nickname : vcard.getNicknames()) { 214 | List nicknameValues = nickname.getValues(); 215 | if (nicknameValues.isEmpty()) { 216 | continue; 217 | } 218 | 219 | for (String nicknameValue : nicknameValues) { 220 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE); 221 | cv.put(ContactsContract.CommonDataKinds.Nickname.NAME, nicknameValue); 222 | contentValues.add(cv); 223 | } 224 | } 225 | } 226 | 227 | private void convertPhones(List contentValues, VCard vcard) { 228 | for (Telephone telephone : vcard.getTelephoneNumbers()) { 229 | String value = telephone.getText(); 230 | TelUri uri = telephone.getUri(); 231 | if (isEmpty(value)) { 232 | if (uri == null) { 233 | continue; 234 | } 235 | value = uri.toString(); 236 | } 237 | 238 | int phoneKind = DataMappings.getPhoneType(telephone); 239 | 240 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); 241 | cv.put(ContactsContract.CommonDataKinds.Phone.NUMBER, value); 242 | cv.put(ContactsContract.CommonDataKinds.Phone.TYPE, phoneKind); 243 | contentValues.add(cv); 244 | } 245 | } 246 | 247 | private void convertEmails(List contentValues, VCard vcard) { 248 | for (Email email : vcard.getEmails()) { 249 | String value = email.getValue(); 250 | if (isEmpty(value)) { 251 | continue; 252 | } 253 | 254 | int emailKind = DataMappings.getEmailType(email); 255 | 256 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE); 257 | cv.put(ContactsContract.CommonDataKinds.Email.ADDRESS, value); 258 | cv.put(ContactsContract.CommonDataKinds.Email.TYPE, emailKind); 259 | contentValues.add(cv); 260 | } 261 | } 262 | 263 | private void convertAddresses(List contentValues, VCard vcard) { 264 | for (Address address : vcard.getAddresses()) { 265 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE); 266 | 267 | String street = address.getStreetAddress(); 268 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, street); 269 | 270 | String poBox = address.getPoBox(); 271 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.POBOX, poBox); 272 | 273 | String city = address.getLocality(); 274 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, city); 275 | 276 | String state = address.getRegion(); 277 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, state); 278 | 279 | String zipCode = address.getPostalCode(); 280 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, zipCode); 281 | 282 | String country = address.getCountry(); 283 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, country); 284 | 285 | String label = address.getLabel(); 286 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.LABEL, label); 287 | 288 | int addressKind = DataMappings.getAddressType(address); 289 | cv.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, addressKind); 290 | 291 | contentValues.add(cv); 292 | } 293 | } 294 | 295 | private void convertIms(List contentValues, VCard vcard) { 296 | //handle extended properties 297 | for (Map.Entry entry : DataMappings.getImPropertyNameMappings().entrySet()) { 298 | String propertyName = entry.getKey(); 299 | Integer protocolType = entry.getValue(); 300 | List rawProperties = vcard.getExtendedProperties(propertyName); 301 | for (RawProperty rawProperty : rawProperties) { 302 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE); 303 | 304 | String value = rawProperty.getValue(); 305 | cv.put(ContactsContract.CommonDataKinds.Im.DATA, value); 306 | 307 | cv.put(ContactsContract.CommonDataKinds.Im.PROTOCOL, protocolType); 308 | 309 | contentValues.add(cv); 310 | } 311 | } 312 | 313 | //handle IMPP properties 314 | for (Impp impp : vcard.getImpps()) { 315 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE); 316 | 317 | String immpAddress = impp.getHandle(); 318 | cv.put(ContactsContract.CommonDataKinds.Im.DATA, immpAddress); 319 | 320 | int immpProtocolType = DataMappings.getIMTypeFromProtocol(impp.getProtocol()); 321 | cv.put(ContactsContract.CommonDataKinds.Im.PROTOCOL, immpProtocolType); 322 | 323 | contentValues.add(cv); 324 | } 325 | } 326 | 327 | private void convertCustomFields(List contentValues, VCard vcard) { 328 | for (AndroidCustomField customField : vcard.getProperties(AndroidCustomField.class)) { 329 | List values = customField.getValues(); 330 | if (values.isEmpty()) { 331 | continue; 332 | } 333 | 334 | NonEmptyContentValues cv; 335 | if (customField.isNickname()) { 336 | cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE); 337 | cv.put(ContactsContract.CommonDataKinds.Nickname.NAME, values.get(0)); 338 | } else if (customField.isContactEvent()) { 339 | cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE); 340 | cv.put(ContactsContract.CommonDataKinds.Event.START_DATE, values.get(0)); 341 | cv.put(ContactsContract.CommonDataKinds.Event.TYPE, values.get(1)); 342 | } else if (customField.isRelation()) { 343 | cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Relation.CONTENT_ITEM_TYPE); 344 | cv.put(ContactsContract.CommonDataKinds.Relation.NAME, values.get(0)); 345 | cv.put(ContactsContract.CommonDataKinds.Relation.TYPE, values.get(1)); 346 | } else { 347 | continue; 348 | } 349 | 350 | contentValues.add(cv); 351 | } 352 | } 353 | 354 | private void convertGroupedProperties(List contentValues, VCard vcard) { 355 | List extendedProperties = vcard.getExtendedProperties(); 356 | Map> orderedByGroup = orderPropertiesByGroup(extendedProperties); 357 | final int ABDATE = 1, ABRELATEDNAMES = 2; 358 | 359 | for (List properties : orderedByGroup.values()) { 360 | if (properties.size() == 1) { 361 | continue; 362 | } 363 | 364 | String label = null; 365 | String val = null; 366 | int mime = 0; 367 | for (RawProperty property : properties) { 368 | String name = property.getPropertyName(); 369 | 370 | if (name.equalsIgnoreCase("X-ABDATE")) { 371 | label = property.getValue(); //date 372 | mime = ABDATE; 373 | continue; 374 | } 375 | 376 | if (name.equalsIgnoreCase("X-ABRELATEDNAMES")) { 377 | label = property.getValue(); //name 378 | mime = ABRELATEDNAMES; 379 | continue; 380 | } 381 | 382 | if (name.equalsIgnoreCase("X-ABLABEL")) { 383 | val = property.getValue(); // type of value ..Birthday,anniversary 384 | continue; 385 | } 386 | } 387 | 388 | NonEmptyContentValues cv = null; 389 | switch (mime) { 390 | case ABDATE: 391 | cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE); 392 | 393 | cv.put(ContactsContract.CommonDataKinds.Event.START_DATE, label); 394 | 395 | int type = DataMappings.getDateType(val); 396 | cv.put(ContactsContract.CommonDataKinds.Event.TYPE, type); 397 | 398 | break; 399 | 400 | case ABRELATEDNAMES: 401 | if (val != null) { 402 | cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE); 403 | cv.put(ContactsContract.CommonDataKinds.Nickname.NAME, label); 404 | 405 | if (!val.equals("Nickname")) { 406 | type = DataMappings.getNameType(val); 407 | cv.put(ContactsContract.CommonDataKinds.Relation.TYPE, type); 408 | } 409 | } 410 | 411 | break; 412 | 413 | default: 414 | continue; 415 | } 416 | 417 | contentValues.add(cv); 418 | } 419 | } 420 | 421 | private void convertBirthdays(List contentValues, VCard vcard) { 422 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); 423 | for (Birthday birthday : vcard.getBirthdays()) { 424 | Date date = birthday.getDate(); 425 | if (date == null) { 426 | continue; 427 | } 428 | 429 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE); 430 | cv.put(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY); 431 | cv.put(ContactsContract.CommonDataKinds.Event.START_DATE, df.format(date)); 432 | contentValues.add(cv); 433 | } 434 | } 435 | 436 | private void convertWebsites(List contentValues, VCard vcard) { 437 | for (Url url : vcard.getUrls()) { 438 | String urlValue = url.getValue(); 439 | if (isEmpty(urlValue)) { 440 | continue; 441 | } 442 | 443 | int type = DataMappings.getWebSiteType(url.getType()); 444 | 445 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE); 446 | cv.put(ContactsContract.CommonDataKinds.Website.URL, urlValue); 447 | cv.put(ContactsContract.CommonDataKinds.Website.TYPE, type); 448 | contentValues.add(cv); 449 | } 450 | } 451 | 452 | private void convertNotes(List contentValues, VCard vcard) { 453 | for (Note note : vcard.getNotes()) { 454 | String noteValue = note.getValue(); 455 | 456 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE); 457 | cv.put(ContactsContract.CommonDataKinds.Note.NOTE, noteValue); 458 | contentValues.add(cv); 459 | } 460 | } 461 | 462 | private void convertPhotos(List contentValues, VCard vcard) { 463 | for (Photo photo : vcard.getPhotos()) { 464 | byte[] data = photo.getData(); 465 | 466 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE); 467 | cv.put(ContactsContract.CommonDataKinds.Photo.PHOTO, data); 468 | contentValues.add(cv); 469 | } 470 | } 471 | 472 | private void convertOrganization(List contentValues, VCard vcard) { 473 | NonEmptyContentValues cv = new NonEmptyContentValues(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); 474 | 475 | Organization organization = vcard.getOrganization(); 476 | if (organization != null) { 477 | List values = organization.getValues(); 478 | String keys[] = { ContactsContract.CommonDataKinds.Organization.COMPANY, ContactsContract.CommonDataKinds.Organization.DEPARTMENT, ContactsContract.CommonDataKinds.Organization.OFFICE_LOCATION }; 479 | for (int i = 0; i < values.size(); i++) { 480 | String key = keys[i]; 481 | String value = values.get(i); 482 | cv.put(key, value); 483 | } 484 | } 485 | 486 | List titleList = vcard.getTitles(); 487 | if (!titleList.isEmpty()) { 488 | cv.put(ContactsContract.CommonDataKinds.Organization.TITLE, titleList.get(0).getValue()); 489 | } 490 | 491 | contentValues.add(cv); 492 | } 493 | 494 | /** 495 | * Groups properties by their group name. 496 | * @param properties the properties to group 497 | * @return a map where the key is the group name (null for no group) and the 498 | * value is the list of properties that belong to that group 499 | */ 500 | private <T extends VCardProperty> Map<String, List<T>> orderPropertiesByGroup(List<T> properties) { 501 | Map<String, List<T>> groupedProperties = new HashMap<String, List<T>>(); 502 | 503 | for (T property : properties) { 504 | String group = property.getGroup(); 505 | if (isEmpty(group)) { 506 | continue; 507 | } 508 | 509 | List<T> groupPropertiesList = groupedProperties.get(group); 510 | if (groupPropertiesList == null) { 511 | groupPropertiesList = new ArrayList<T>(); 512 | groupedProperties.put(group, groupPropertiesList); 513 | } 514 | groupPropertiesList.add(property); 515 | } 516 | 517 | return groupedProperties; 518 | } 519 | 520 | /** 521 | * A wrapper for {@link ContentValues} that only adds values which are 522 | * non-null and non-empty (in the case of Strings). 523 | */ 524 | private static class NonEmptyContentValues { 525 | private final ContentValues contentValues = new ContentValues(); 526 | private final String contentItemType; 527 | 528 | public NonEmptyContentValues() { 529 | this(null); 530 | } 531 | 532 | /** 533 | * @param contentItemType the MIME type (value of 534 | * {@link ContactsContract.Contacts.Data#MIMETYPE}) 535 | */ 536 | public NonEmptyContentValues(String contentItemType) { 537 | this.contentItemType = contentItemType; 538 | } 539 | 540 | public void put(String key, String value) { 541 | if (isEmpty(value)) { 542 | return; 543 | } 544 | contentValues.put(key, value); 545 | } 546 | 547 | public void put(String key, int value) { 548 | contentValues.put(key, value); 549 | } 550 | 551 | public void put(String key, byte[] value) { 552 | if (value == null) { 553 | return; 554 | } 555 | contentValues.put(key, value); 556 | } 557 | 558 | /** 559 | * Gets the wrapped {@link ContentValues} object, adding the MIME type 560 | * entry if the values map is not empty. 561 | * @return the wrapped {@link ContentValues} object 562 | */ 563 | public ContentValues getContentValues() { 564 | if (contentValues.size() > 0 && contentItemType != null) { 565 | put(ContactsContract.Contacts.Data.MIMETYPE, contentItemType); 566 | } 567 | return contentValues; 568 | } 569 | } 570 | } 571 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/java/ezvcard/android/DataMappings.java: -------------------------------------------------------------------------------- 1 | package ezvcard.android; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import android.provider.ContactsContract; 8 | import ezvcard.parameter.AddressType; 9 | import ezvcard.parameter.EmailType; 10 | import ezvcard.parameter.TelephoneType; 11 | import ezvcard.property.Address; 12 | import ezvcard.property.Email; 13 | import ezvcard.property.Impp; 14 | import ezvcard.property.Telephone; 15 | 16 | /* 17 | Copyright (c) 2014-2015, Michael Angstadt 18 | All rights reserved. 19 | 20 | Redistribution and use in source and binary forms, with or without 21 | modification, are permitted provided that the following conditions are met: 22 | 23 | 1. Redistributions of source code must retain the above copyright notice, this 24 | list of conditions and the following disclaimer. 25 | 2. Redistributions in binary form must reproduce the above copyright notice, 26 | this list of conditions and the following disclaimer in the documentation 27 | and/or other materials provided with the distribution. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 33 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | The views and conclusions contained in the software and documentation are those 41 | of the authors and should not be interpreted as representing official policies, 42 | either expressed or implied, of the FreeBSD Project. 43 | */ 44 | 45 | /** 46 | * Maps between vCard contact data types and Android {@link ContactsContract} 47 | * data types. 48 | * 49 | * @author Pratyush 50 | * @author Julien Garrigou 51 | * @author Michael Angstadt 52 | */ 53 | public class DataMappings { 54 | private static final Map<TelephoneType, Integer> phoneTypeMappings; 55 | static { 56 | Map<TelephoneType, Integer> m = new HashMap<TelephoneType, Integer>(); 57 | m.put(TelephoneType.BBS, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM); 58 | m.put(TelephoneType.CAR, ContactsContract.CommonDataKinds.Phone.TYPE_CAR); 59 | m.put(TelephoneType.CELL, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE); 60 | m.put(TelephoneType.FAX, ContactsContract.CommonDataKinds.Phone.TYPE_FAX_HOME); 61 | m.put(TelephoneType.HOME, ContactsContract.CommonDataKinds.Phone.TYPE_HOME); 62 | m.put(TelephoneType.ISDN, ContactsContract.CommonDataKinds.Phone.TYPE_ISDN); 63 | m.put(TelephoneType.MODEM, ContactsContract.CommonDataKinds.Phone.TYPE_OTHER); 64 | m.put(TelephoneType.PAGER, ContactsContract.CommonDataKinds.Phone.TYPE_PAGER); 65 | m.put(TelephoneType.MSG, ContactsContract.CommonDataKinds.Phone.TYPE_MMS); 66 | m.put(TelephoneType.PCS, ContactsContract.CommonDataKinds.Phone.TYPE_OTHER); 67 | m.put(TelephoneType.TEXT, ContactsContract.CommonDataKinds.Phone.TYPE_MMS); 68 | m.put(TelephoneType.TEXTPHONE, ContactsContract.CommonDataKinds.Phone.TYPE_MMS); 69 | m.put(TelephoneType.VIDEO, ContactsContract.CommonDataKinds.Phone.TYPE_OTHER); 70 | m.put(TelephoneType.WORK, ContactsContract.CommonDataKinds.Phone.TYPE_WORK); 71 | m.put(TelephoneType.VOICE, ContactsContract.CommonDataKinds.Phone.TYPE_OTHER); 72 | phoneTypeMappings = Collections.unmodifiableMap(m); 73 | } 74 | 75 | private static final Map<String, Integer> websiteTypeMappings; 76 | static { 77 | Map<String, Integer> m = new HashMap<String, Integer>(); 78 | m.put("home", ContactsContract.CommonDataKinds.Website.TYPE_HOME); 79 | m.put("work", ContactsContract.CommonDataKinds.Website.TYPE_WORK); 80 | m.put("homepage", ContactsContract.CommonDataKinds.Website.TYPE_HOMEPAGE); 81 | m.put("profile", ContactsContract.CommonDataKinds.Website.TYPE_PROFILE); 82 | websiteTypeMappings = Collections.unmodifiableMap(m); 83 | } 84 | 85 | private static final Map<EmailType, Integer> emailTypeMappings; 86 | static { 87 | Map<EmailType, Integer> m = new HashMap<EmailType, Integer>(); 88 | m.put(EmailType.HOME, ContactsContract.CommonDataKinds.Email.TYPE_HOME); 89 | m.put(EmailType.WORK, ContactsContract.CommonDataKinds.Email.TYPE_WORK); 90 | emailTypeMappings = Collections.unmodifiableMap(m); 91 | } 92 | 93 | private static final Map<AddressType, Integer> addressTypeMappings; 94 | static { 95 | Map<AddressType, Integer> m = new HashMap<AddressType, Integer>(); 96 | m.put(AddressType.HOME, ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME); 97 | m.put(AddressType.get("business"), ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK); 98 | m.put(AddressType.WORK, ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK); 99 | m.put(AddressType.get("other"), ContactsContract.CommonDataKinds.StructuredPostal.TYPE_OTHER); 100 | addressTypeMappings = Collections.unmodifiableMap(m); 101 | } 102 | 103 | private static final Map<String, Integer> abRelatedNamesMappings; 104 | static { 105 | Map<String, Integer> m = new HashMap<String, Integer>(); 106 | m.put("father", ContactsContract.CommonDataKinds.Relation.TYPE_FATHER); 107 | m.put("spouse", ContactsContract.CommonDataKinds.Relation.TYPE_SPOUSE); 108 | m.put("mother", ContactsContract.CommonDataKinds.Relation.TYPE_MOTHER); 109 | m.put("brother", ContactsContract.CommonDataKinds.Relation.TYPE_BROTHER); 110 | m.put("parent", ContactsContract.CommonDataKinds.Relation.TYPE_PARENT); 111 | m.put("sister", ContactsContract.CommonDataKinds.Relation.TYPE_SISTER); 112 | m.put("child", ContactsContract.CommonDataKinds.Relation.TYPE_CHILD); 113 | m.put("assistant", ContactsContract.CommonDataKinds.Relation.TYPE_ASSISTANT); 114 | m.put("partner", ContactsContract.CommonDataKinds.Relation.TYPE_PARTNER); 115 | m.put("manager", ContactsContract.CommonDataKinds.Relation.TYPE_MANAGER); 116 | abRelatedNamesMappings = Collections.unmodifiableMap(m); 117 | } 118 | 119 | private static final Map<String, Integer> abDateMappings; 120 | static { 121 | Map<String, Integer> m = new HashMap<String, Integer>(); 122 | m.put("anniversary", ContactsContract.CommonDataKinds.Event.TYPE_ANNIVERSARY); 123 | m.put("other", ContactsContract.CommonDataKinds.Event.TYPE_OTHER); 124 | abDateMappings = Collections.unmodifiableMap(m); 125 | } 126 | 127 | private static final Map<String, Integer> imPropertyNameMappings; 128 | static{ 129 | Map<String, Integer> m = new HashMap<String, Integer>(); 130 | m.put("X-AIM", ContactsContract.CommonDataKinds.Im.PROTOCOL_AIM); 131 | m.put("X-ICQ", ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ); 132 | m.put("X-QQ", ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ); 133 | m.put("X-GOOGLE-TALK", ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM); 134 | m.put("X-JABBER", ContactsContract.CommonDataKinds.Im.PROTOCOL_JABBER); 135 | m.put("X-MSN", ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN); 136 | m.put("X-MS-IMADDRESS", ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN); 137 | m.put("X-YAHOO", ContactsContract.CommonDataKinds.Im.PROTOCOL_YAHOO); 138 | m.put("X-SKYPE", ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE); 139 | m.put("X-SKYPE-USERNAME", ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE); 140 | m.put("X-TWITTER", ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM); 141 | imPropertyNameMappings = Collections.unmodifiableMap(m); 142 | } 143 | 144 | private static final Map<String, Integer> imProtocolMappings; 145 | static{ 146 | Map<String, Integer> m = new HashMap<String, Integer>(); 147 | m.put("aim", ContactsContract.CommonDataKinds.Im.PROTOCOL_AIM); 148 | m.put("icq", ContactsContract.CommonDataKinds.Im.PROTOCOL_ICQ); 149 | m.put("msn", ContactsContract.CommonDataKinds.Im.PROTOCOL_MSN); 150 | m.put("ymsgr", ContactsContract.CommonDataKinds.Im.PROTOCOL_YAHOO); 151 | m.put("skype", ContactsContract.CommonDataKinds.Im.PROTOCOL_SKYPE); 152 | imProtocolMappings = Collections.unmodifiableMap(m); 153 | } 154 | 155 | /** 156 | * Maps the value of a URL property's TYPE parameter to the appropriate 157 | * Android {@link ContactsContract.CommonDataKinds.Website} value. 158 | * @param type the TYPE parameter value (can be null) 159 | * @return the Android type 160 | */ 161 | public static int getWebSiteType(String type) { 162 | if (type == null){ 163 | return ContactsContract.CommonDataKinds.Website.TYPE_CUSTOM; 164 | } 165 | 166 | type = type.toLowerCase(); 167 | Integer value = websiteTypeMappings.get(type); 168 | return (value == null) ? ContactsContract.CommonDataKinds.Website.TYPE_CUSTOM : value; 169 | } 170 | 171 | /** 172 | * Maps the value of a X-ABLABEL property to the appropriate 173 | * Android {@link ContactsContract.CommonDataKinds.Event} value. 174 | * @param type the property value 175 | * @return the Android type 176 | */ 177 | public static int getDateType(String type) { 178 | if (type == null) { 179 | return ContactsContract.CommonDataKinds.Event.TYPE_OTHER; 180 | } 181 | 182 | type = type.toLowerCase(); 183 | for (Map.Entry<String, Integer> entry : abDateMappings.entrySet()){ 184 | if (type.contains(entry.getKey())){ 185 | return entry.getValue(); 186 | } 187 | } 188 | return ContactsContract.CommonDataKinds.Event.TYPE_OTHER; 189 | } 190 | 191 | /** 192 | * Maps the value of a X-ABLABEL property to the appropriate 193 | * Android {@link ContactsContract.CommonDataKinds.Relation} value. 194 | * @param type the property value 195 | * @return the Android type 196 | */ 197 | public static int getNameType(String type) { 198 | if (type == null) { 199 | return ContactsContract.CommonDataKinds.Relation.TYPE_CUSTOM; 200 | } 201 | 202 | type = type.toLowerCase(); 203 | for (Map.Entry<String, Integer> entry : abRelatedNamesMappings.entrySet()){ 204 | if (type.contains(entry.getKey())){ 205 | return entry.getValue(); 206 | } 207 | } 208 | return ContactsContract.CommonDataKinds.Relation.TYPE_CUSTOM; 209 | } 210 | 211 | /** 212 | * Gets the mappings that associate an extended property name (e.g. "X-AIM") 213 | * with its appropriate Android {@link ContactsContract.CommonDataKinds.Im} 214 | * value. 215 | * @return the mappings (the key is the property name, the value is the Android value) 216 | */ 217 | public static Map<String, Integer> getImPropertyNameMappings(){ 218 | return imPropertyNameMappings; 219 | } 220 | 221 | /** 222 | * Converts an IM protocol from a {@link Impp} property (e.g. "aim") to the 223 | * appropriate Android {@link ContactsContract.CommonDataKinds.Im} value. 224 | * @param protocol the IM protocol (e.g. "aim", can be null) 225 | * @return the Android value 226 | */ 227 | public static int getIMTypeFromProtocol(String protocol) { 228 | if (protocol == null){ 229 | return ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM; 230 | } 231 | 232 | protocol = protocol.toLowerCase(); 233 | Integer value = imProtocolMappings.get(protocol); 234 | return (value == null) ? ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM : value; 235 | } 236 | 237 | /** 238 | * Determines the appropriate Android 239 | * {@link ContactsContract.CommonDataKinds.Phone} value for a 240 | * {@link Telephone} property. 241 | * @param property the property 242 | * @return the Android type value 243 | */ 244 | public static int getPhoneType(Telephone property) { 245 | for (TelephoneType type : property.getTypes()){ 246 | Integer androidType = phoneTypeMappings.get(type); 247 | if (androidType != null){ 248 | return androidType; 249 | } 250 | } 251 | return ContactsContract.CommonDataKinds.Phone.TYPE_OTHER; 252 | } 253 | 254 | /** 255 | * Determines the appropriate Android 256 | * {@link ContactsContract.CommonDataKinds.Email} value for an {@link Email} 257 | * property. 258 | * @param property the property 259 | * @return the Android type value 260 | */ 261 | public static int getEmailType(Email property) { 262 | for (EmailType type : property.getTypes()){ 263 | Integer androidType = emailTypeMappings.get(type); 264 | if (androidType != null){ 265 | return androidType; 266 | } 267 | } 268 | return ContactsContract.CommonDataKinds.Email.TYPE_OTHER; 269 | } 270 | 271 | /** 272 | * Determines the appropriate Android 273 | * {@link ContactsContract.CommonDataKinds.StructuredPostal} value for an 274 | * {@link Address} property. 275 | * @param property the property 276 | * @return the Android type value 277 | */ 278 | public static int getAddressType(Address property) { 279 | for (AddressType type : property.getTypes()){ 280 | Integer androidType = addressTypeMappings.get(type); 281 | if (androidType != null){ 282 | return androidType; 283 | } 284 | } 285 | return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_CUSTOM; 286 | } 287 | 288 | private DataMappings(){ 289 | //hide constructor 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | <resources> 2 | <!-- Example customization of dimensions originally defined in res/values/dimens.xml 3 | (such as screen margins) for screens with more than 820dp of available width. This 4 | would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> 5 | <dimen name="activity_horizontal_margin">64dp</dimen> 6 | </resources> 7 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | <resources> 2 | <!-- Default screen margins, per the Android Design guidelines. --> 3 | <dimen name="activity_horizontal_margin">16dp</dimen> 4 | <dimen name="activity_vertical_margin">16dp</dimen> 5 | 6 | </resources> 7 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <resources> 3 | 4 | <string name="app_name">android-mapper</string> 5 | <string name="title_activity_vcard_parser">VcardParser</string> 6 | <string name="hello_world">Hello world!</string> 7 | <string name="action_settings">Settings</string> 8 | 9 | </resources> 10 | -------------------------------------------------------------------------------- /vcard-androidParser/src/main/resources/ez-vcard-android.license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015, Mike Angstadt 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of ez-vcard-android nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | --------------------------------------------------------------------------------