@aalzehla/capacitor-contacts 0.0.5 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/{AalzehlaCapacitorContacts.podspec → CapacitorCommunityContacts.podspec} +3 -3
  2. package/README.md +69 -45
  3. package/android/build.gradle +15 -12
  4. package/android/src/main/java/getcapacitor/community/contacts/BiMap.java +45 -0
  5. package/android/src/main/java/getcapacitor/community/contacts/ContactPayload.java +286 -0
  6. package/android/src/main/java/getcapacitor/community/contacts/Contacts.java +384 -0
  7. package/android/src/main/java/getcapacitor/community/contacts/ContactsPlugin.java +255 -0
  8. package/android/src/main/java/getcapacitor/community/contacts/CreateContactInput.java +233 -0
  9. package/android/src/main/java/getcapacitor/community/contacts/GetContactsProjectionInput.java +214 -0
  10. package/dist/esm/definitions.d.ts +285 -19
  11. package/dist/esm/definitions.js +47 -1
  12. package/dist/esm/definitions.js.map +1 -1
  13. package/dist/esm/index.d.ts +3 -3
  14. package/dist/esm/index.js +3 -3
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/web.d.ts +9 -7
  17. package/dist/esm/web.js +21 -7
  18. package/dist/esm/web.js.map +1 -1
  19. package/dist/plugin.cjs.js +73 -14
  20. package/dist/plugin.cjs.js.map +1 -1
  21. package/dist/plugin.js +74 -15
  22. package/dist/plugin.js.map +1 -1
  23. package/ios/Plugin/BiMap.swift +42 -0
  24. package/ios/Plugin/ContactPayload.swift +227 -0
  25. package/ios/Plugin/Contacts.swift +227 -0
  26. package/ios/Plugin/ContactsPlugin.h +10 -0
  27. package/ios/Plugin/ContactsPlugin.m +14 -0
  28. package/ios/Plugin/ContactsPlugin.swift +221 -0
  29. package/ios/Plugin/CreateContactInput.swift +187 -0
  30. package/ios/Plugin/GetContactsProjectionInput.swift +119 -0
  31. package/ios/Plugin/Info.plist +24 -0
  32. package/package.json +33 -30
  33. package/Package.swift +0 -28
  34. package/android/src/main/java/com/aalzehla/capacitor/contacts/CapacitorContactsPlugin.java +0 -177
  35. package/android/src/main/java/com/aalzehla/capacitor/contacts/ContactDataExtractorVisitor.java +0 -122
  36. package/android/src/main/java/com/aalzehla/capacitor/contacts/ContactExtractorVisitor.java +0 -31
  37. package/android/src/main/java/com/aalzehla/capacitor/contacts/PluginContactFields.java +0 -17
  38. package/android/src/main/java/com/aalzehla/capacitor/contacts/contentQuery/ContentQuery.java +0 -83
  39. package/android/src/main/java/com/aalzehla/capacitor/contacts/contentQuery/ContentQueryService.java +0 -60
  40. package/android/src/main/java/com/aalzehla/capacitor/contacts/utils/Utils.java +0 -19
  41. package/android/src/main/java/com/aalzehla/capacitor/contacts/utils/Visitable.java +0 -5
  42. package/android/src/main/java/com/aalzehla/capacitor/contacts/utils/Visitor.java +0 -5
  43. package/dist/docs.json +0 -145
  44. package/ios/Sources/CapacitorContactsPlugin/CapacitorContactsPlugin.swift +0 -168
  45. package/ios/Tests/CapacitorContactsPluginTests/CapacitorContactsPluginTests.swift +0 -15
@@ -3,15 +3,15 @@ require 'json'
3
3
  package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
4
 
5
5
  Pod::Spec.new do |s|
6
- s.name = 'AalzehlaCapacitorContacts'
6
+ s.name = 'CapacitorCommunityContacts'
7
7
  s.version = package['version']
8
8
  s.summary = package['description']
9
9
  s.license = package['license']
10
10
  s.homepage = package['repository']['url']
11
11
  s.author = package['author']
12
12
  s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
- s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
- s.ios.deployment_target = '14.0'
13
+ s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '15.0'
15
15
  s.dependency 'Capacitor'
16
16
  s.swift_version = '5.1'
17
17
  end
package/README.md CHANGED
@@ -1,67 +1,91 @@
1
- # capacitor-contacts
1
+ <p align="center">
2
+ <img
3
+ src="https://user-images.githubusercontent.com/236501/85893648-1c92e880-b7a8-11ea-926d-95355b8175c7.png"
4
+ width="128"
5
+ height="128"
6
+ />
7
+ </p>
2
8
 
3
- This capacitor plugin allows you to use the native contact picker UI on Android or iOS for single contact selection. Both platforms will return the same payload structure, where the data exists.
9
+ <h3 id="home" align="center">
10
+ Contacts
11
+ </h3>
4
12
 
5
- ## Install
13
+ <p align="center">
14
+ <strong>
15
+ <code>@capacitor-community/contacts</code>
16
+ </strong>
17
+ </p>
6
18
 
7
- ```bash
8
- npm install @aalzehla/capacitor-contacts
9
- npx cap sync
10
- ```
19
+ <p align="center">Capacitor Plugin for accessing Contacts.</p>
11
20
 
12
- ## API
21
+ <p align="center">
22
+ <img src="https://img.shields.io/badge/supported%20capacitor%20versions-v3,%20v4,%20v5,%20v6%20and%20v7-blue?logo=Capacitor&style=flat-square" />
23
+ <img src="https://img.shields.io/maintenance/yes/2026?style=flat-square" />
24
+ <a href="https://www.npmjs.com/package/@capacitor-community/contacts">
25
+ <img src="https://img.shields.io/npm/l/@capacitor-community/contacts?style=flat-square" />
26
+ </a>
27
+ <br>
28
+ <a href="https://www.npmjs.com/package/@capacitor-community/contacts">
29
+ <img src="https://img.shields.io/npm/dw/@capacitor-community/contacts?style=flat-square" />
30
+ </a>
31
+ <a href="https://www.npmjs.com/package/@capacitor-community/contacts">
32
+ <img src="https://img.shields.io/npm/v/@capacitor-community/contacts?style=flat-square" />
33
+ </a>
34
+ </p>
13
35
 
14
- <docgen-index>
36
+ ## Purpose
15
37
 
16
- * [`open()`](#open)
17
- * [`close()`](#close)
18
- * [Interfaces](#interfaces)
38
+ This plugin enables you to access the native contacts APIs of iOS and Android. It allows you to retrieve, create and delete contacts.
19
39
 
20
- </docgen-index>
40
+ ## Versions
21
41
 
22
- <docgen-api>
23
- <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
42
+ Currently there are three actively maintained versions of this plugin. The API of these versions is identical. The only difference between these versions is the supported Capacitor versions.
24
43
 
25
- ### open()
44
+ | Plugin | Capacitor | Status | Documentation |
45
+ | ------ | --------- | ------ | ------------------------------------------------------- |
46
+ | v7.x | v7.x | LTS | [Link](https://capacitor-community.github.io/contacts/) |
47
+ | v6.x | v6.x | LTS | [Link](https://capacitor-community.github.io/contacts/) |
48
+ | v5.x | v5.x | LTS | [Link](https://capacitor-community.github.io/contacts/) |
49
+ | v4.x | v4.x | LTS | [Link](https://capacitor-community.github.io/contacts/) |
50
+ | v3.x | v3.x | LTS | [Link](https://capacitor-community.github.io/contacts/) |
26
51
 
27
- ```typescript
28
- open() => Promise<Contact[]>
29
- ```
52
+ If you are installing this plugin into a new project, you can ignore the following explanation.
30
53
 
31
- **Returns:** <code>Promise&lt;Contact[]&gt;</code>
54
+ In the past a few other versions of this plugin were released, also targeting different versions of Capacitor:
32
55
 
33
- --------------------
56
+ | Plugin | Capacitor | Status | Documentation |
57
+ | ------------- | --------- | ---------- | --------------------------------------------------------------------------------------------------------------- |
58
+ | v2.x | v4.x | Deprecated | [Link](https://github.com/capacitor-community/contacts/blob/v2.0.0/README.md) |
59
+ | v1.0.9 and up | v3.x | Deprecated | [Link](https://github.com/capacitor-community/contacts/blob/1.1.3/README.md) |
60
+ | v1.0.0 and up | v2.x | Deprecated | [Link](https://github.com/capacitor-community/contacts/blob/0cb99be68dc8ee4547c75f932872bd065f5509d2/README.md) |
61
+ | v0.x | v2.x | Deprecated | [Link](https://github.com/capacitor-community/contacts/blob/0.1.1/README.md) |
34
62
 
63
+ Admittedly, this wasn't the most consistent versioning strategy, and we'll keep it more coherent in the future.
35
64
 
36
- ### close()
65
+ It's highly recommended to upgrade to either v3, v4, v5, v6 or v7 if you are using an old version!
37
66
 
38
- ```typescript
39
- close() => Promise<void>
40
- ```
67
+ <p class="hide-next-element"></p>
41
68
 
42
- --------------------
69
+ ## Documentation
43
70
 
71
+ <p class="hide-next-element"></p>
44
72
 
45
- ### Interfaces
73
+ Extensive documentation is available [here](https://capacitor-community.github.io/contacts/).
46
74
 
75
+ <p class="hide-next-element"></p>
47
76
 
48
- #### Contact
77
+ ## Shortcuts
49
78
 
50
- | Prop | Type |
51
- | ----------------------------- | ------------------- |
52
- | **`identifier`** | <code>string</code> |
53
- | **`androidContactLookupKey`** | <code>string</code> |
54
- | **`contactId`** | <code>string</code> |
55
- | **`givenName`** | <code>string</code> |
56
- | **`familyName`** | <code>string</code> |
57
- | **`nickname`** | <code>string</code> |
58
- | **`fullName`** | <code>string</code> |
59
- | **`jobTitle`** | <code>string</code> |
60
- | **`departmentName`** | <code>string</code> |
61
- | **`organizationName`** | <code>string</code> |
62
- | **`note`** | <code>string</code> |
63
- | **`phoneNumbers`** | <code>any[]</code> |
64
- | **`emailAddresses`** | <code>any[]</code> |
65
- | **`postalAddresses`** | <code>any[]</code> |
79
+ <p class="hide-next-element"></p>
66
80
 
67
- </docgen-api>
81
+ - [Documentation homepage](https://capacitor-community.github.io/contacts/)
82
+
83
+ - [Installation](https://capacitor-community.github.io/contacts/#/getting-started-installation)
84
+
85
+ - [API reference](https://capacitor-community.github.io/contacts/#/api)
86
+
87
+ <!-- - [Examples](https://github.com/capacitor-community/contacts-examples) -->
88
+
89
+ ## Limitations
90
+
91
+ This plugins only adds support for using the native iOS and Android APIs. If you want to make use of the JavaScript API as well (for a possible webapp) you should implement that separately. Of course it should be possible to integrate this into the plugin in the future. If you want to help out with this, please start a PR.
@@ -1,8 +1,8 @@
1
1
  ext {
2
2
  junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
- androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
4
- androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
5
- androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
6
6
  }
7
7
 
8
8
  buildscript {
@@ -11,34 +11,38 @@ buildscript {
11
11
  mavenCentral()
12
12
  }
13
13
  dependencies {
14
- classpath 'com.android.tools.build:gradle:8.2.1'
14
+ classpath 'com.android.tools.build:gradle:8.13.0'
15
15
  }
16
16
  }
17
17
 
18
18
  apply plugin: 'com.android.library'
19
19
 
20
20
  android {
21
- namespace "com.aalzehla.capacitor.contacts"
22
- compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
21
+ namespace = "getcapacitor.community.contacts"
22
+ compileSdkVersion(project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35)
23
+
23
24
  defaultConfig {
24
- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
25
- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
25
+ minSdkVersion(project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23)
26
+ targetSdkVersion(project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35)
26
27
  versionCode 1
27
28
  versionName "1.0"
28
29
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
30
  }
31
+
30
32
  buildTypes {
31
33
  release {
32
34
  minifyEnabled false
33
35
  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
36
  }
35
37
  }
38
+
36
39
  lintOptions {
37
- abortOnError false
40
+ abortOnError = false
38
41
  }
42
+
39
43
  compileOptions {
40
- sourceCompatibility JavaVersion.VERSION_17
41
- targetCompatibility JavaVersion.VERSION_17
44
+ sourceCompatibility JavaVersion.VERSION_21
45
+ targetCompatibility JavaVersion.VERSION_21
42
46
  }
43
47
  }
44
48
 
@@ -47,7 +51,6 @@ repositories {
47
51
  mavenCentral()
48
52
  }
49
53
 
50
-
51
54
  dependencies {
52
55
  implementation fileTree(dir: 'libs', include: ['*.jar'])
53
56
  implementation project(':capacitor-android')
@@ -0,0 +1,45 @@
1
+ package getcapacitor.community.contacts;
2
+
3
+ import java.util.HashMap;
4
+
5
+ // Helper to enable bidirectional mapping.
6
+ public class BiMap<K, V> {
7
+
8
+ // The following map can be used for retrieving the key belonging to a certain value.
9
+ // This map is essentially the inverted version of `mapForValues`
10
+ private final HashMap<V, K> mapForKeys = new HashMap<>();
11
+ // The following map can be used for retrieving the value belonging to a certain key.
12
+ private final HashMap<K, V> mapForValues;
13
+
14
+ private final K defaultKey;
15
+ private final V defaultValue;
16
+
17
+ BiMap(HashMap<K, V> map, K defaultKey, V defaultValue) {
18
+ this.mapForValues = map;
19
+
20
+ for (HashMap.Entry<K, V> entry : map.entrySet()) {
21
+ K key = entry.getKey();
22
+ V value = entry.getValue();
23
+ this.mapForKeys.put(value, key);
24
+ }
25
+
26
+ this.defaultKey = defaultKey;
27
+ this.defaultValue = defaultValue;
28
+ }
29
+
30
+ K getKey(V v) {
31
+ K k = this.mapForKeys.get(v);
32
+ if (k == null) {
33
+ return this.defaultKey;
34
+ }
35
+ return k;
36
+ }
37
+
38
+ V getValue(K k) {
39
+ V v = this.mapForValues.get(k);
40
+ if (v == null) {
41
+ return this.defaultValue;
42
+ }
43
+ return v;
44
+ }
45
+ }
@@ -0,0 +1,286 @@
1
+ package getcapacitor.community.contacts;
2
+
3
+ import android.database.Cursor;
4
+ import android.provider.ContactsContract;
5
+ import android.provider.ContactsContract.CommonDataKinds.Email;
6
+ import android.provider.ContactsContract.CommonDataKinds.Event;
7
+ import android.provider.ContactsContract.CommonDataKinds.Note;
8
+ import android.provider.ContactsContract.CommonDataKinds.Organization;
9
+ import android.provider.ContactsContract.CommonDataKinds.Phone;
10
+ import android.provider.ContactsContract.CommonDataKinds.Photo;
11
+ import android.provider.ContactsContract.CommonDataKinds.StructuredName;
12
+ import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
13
+ import android.provider.ContactsContract.CommonDataKinds.Website;
14
+ import android.util.Base64;
15
+ import androidx.annotation.NonNull;
16
+ import com.getcapacitor.JSArray;
17
+ import com.getcapacitor.JSObject;
18
+ import java.io.BufferedInputStream;
19
+ import java.io.ByteArrayInputStream;
20
+ import java.io.InputStream;
21
+ import java.net.URLConnection;
22
+
23
+ public class ContactPayload {
24
+
25
+ // Id
26
+ private String contactId;
27
+
28
+ // Name
29
+ private JSObject name = new JSObject();
30
+
31
+ // Organization
32
+ private JSObject organization = new JSObject();
33
+
34
+ // Birthday
35
+ private JSObject birthday = new JSObject();
36
+
37
+ // Note
38
+ private String note;
39
+
40
+ // Phones
41
+ private JSArray phones = new JSArray();
42
+
43
+ // Emails
44
+ private JSArray emails = new JSArray();
45
+
46
+ // URLs
47
+ private JSArray urls = new JSArray();
48
+
49
+ // Postal Addresses
50
+ private JSArray postalAddresses = new JSArray();
51
+
52
+ // Image
53
+ private JSObject image = new JSObject();
54
+
55
+ ContactPayload(String contactId) {
56
+ this.contactId = contactId;
57
+ }
58
+
59
+ private static @NonNull String getMimetype(byte[] blob) {
60
+ try {
61
+ InputStream is = new BufferedInputStream(new ByteArrayInputStream(blob));
62
+ String mimeType = URLConnection.guessContentTypeFromStream(is);
63
+ if (mimeType == null) {
64
+ return "image/png";
65
+ }
66
+ return mimeType;
67
+ } catch (Exception e) {
68
+ return "image/png";
69
+ }
70
+ }
71
+
72
+ private Integer parseStrToIntSafe(String str) {
73
+ try {
74
+ return Integer.parseInt(str);
75
+ } catch (NumberFormatException e) {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ private Boolean getBooleanByColumnName(Cursor cursor, String columnName) {
81
+ int index = cursor.getColumnIndex(columnName);
82
+ if (index >= 0) {
83
+ int result = cursor.getInt(index);
84
+ return result == 1;
85
+ }
86
+ return null;
87
+ }
88
+
89
+ private String getStringByColumnName(Cursor cursor, String columnName) {
90
+ int index = cursor.getColumnIndex(columnName);
91
+ if (index >= 0) {
92
+ return cursor.getString(index);
93
+ }
94
+ return null;
95
+ }
96
+
97
+ private Integer getIntByColumnName(Cursor cursor, String columnName) {
98
+ int index = cursor.getColumnIndex(columnName);
99
+ if (index >= 0) {
100
+ return cursor.getInt(index);
101
+ }
102
+ return null;
103
+ }
104
+
105
+ private String getBase64ByColumnName(Cursor cursor, String columnName) {
106
+ int index = cursor.getColumnIndex(columnName);
107
+ if (index >= 0) {
108
+ byte[] blob = cursor.getBlob(index);
109
+ if (blob != null) {
110
+ String mimeType = getMimetype(blob);
111
+ String encodedImage = Base64.encodeToString(blob, Base64.NO_WRAP);
112
+ return "data:" + mimeType + ";base64," + encodedImage;
113
+ }
114
+ }
115
+ return null;
116
+ }
117
+
118
+ public void fillDataByCursor(@NonNull Cursor cursor) {
119
+ String mimeType = getStringByColumnName(cursor, ContactsContract.Data.MIMETYPE);
120
+
121
+ if (mimeType == null) {
122
+ return;
123
+ }
124
+
125
+ switch (mimeType) {
126
+ // Name
127
+ case StructuredName.CONTENT_ITEM_TYPE:
128
+ name.put("display", getStringByColumnName(cursor, StructuredName.DISPLAY_NAME));
129
+ name.put("given", getStringByColumnName(cursor, StructuredName.GIVEN_NAME));
130
+ name.put("middle", getStringByColumnName(cursor, StructuredName.MIDDLE_NAME));
131
+ name.put("family", getStringByColumnName(cursor, StructuredName.FAMILY_NAME));
132
+ name.put("prefix", getStringByColumnName(cursor, StructuredName.PREFIX));
133
+ name.put("suffix", getStringByColumnName(cursor, StructuredName.SUFFIX));
134
+ break;
135
+ // Organization
136
+ case Organization.CONTENT_ITEM_TYPE:
137
+ organization.put("company", getStringByColumnName(cursor, Organization.COMPANY));
138
+ organization.put("jobTitle", getStringByColumnName(cursor, Organization.TITLE));
139
+ organization.put("department", getStringByColumnName(cursor, Organization.DEPARTMENT));
140
+ break;
141
+ // Birthday
142
+ case Event.CONTENT_ITEM_TYPE:
143
+ Integer eventType = getIntByColumnName(cursor, Event.TYPE);
144
+ if (eventType != null && eventType == Event.TYPE_BIRTHDAY) {
145
+ String birthdayString = getStringByColumnName(cursor, Event.START_DATE);
146
+
147
+ if (birthdayString != null) {
148
+ // Normally the date is formatted as "yyyy-mm-dd"
149
+ // But it's possible to not have a year saved to the birthday,
150
+ // then it's formatted like "--mm-dd".
151
+ // So we'll have to rectify that:
152
+ birthdayString = birthdayString.replace("--", "");
153
+
154
+ // Next we'll split the string into pieces:
155
+ String[] splittedBirthdayString = birthdayString.split("-");
156
+
157
+ if (splittedBirthdayString.length == 2) {
158
+ // Birthday is formatted like "mm-dd"
159
+ birthday.put("month", parseStrToIntSafe(splittedBirthdayString[0]));
160
+ birthday.put("day", parseStrToIntSafe(splittedBirthdayString[1]));
161
+ } else if (splittedBirthdayString.length == 3) {
162
+ // Birthday is formatted like "yyyy-mm-dd"
163
+ birthday.put("year", parseStrToIntSafe(splittedBirthdayString[0]));
164
+ birthday.put("month", parseStrToIntSafe(splittedBirthdayString[1]));
165
+ birthday.put("day", parseStrToIntSafe(splittedBirthdayString[2]));
166
+ }
167
+ }
168
+ }
169
+ break;
170
+ // Note
171
+ case Note.CONTENT_ITEM_TYPE:
172
+ note = getStringByColumnName(cursor, Note.NOTE);
173
+ break;
174
+ // Phones
175
+ case Phone.CONTENT_ITEM_TYPE:
176
+ String number = getStringByColumnName(cursor, Phone.NUMBER);
177
+ Integer phoneType = getIntByColumnName(cursor, Phone.TYPE);
178
+ if (number != null && phoneType != null) {
179
+ JSObject phoneObject = new JSObject();
180
+ phoneObject.put("type", Contacts.phoneTypeMap.getKey(phoneType));
181
+ phoneObject.put("label", getStringByColumnName(cursor, Phone.LABEL));
182
+ phoneObject.put("isPrimary", getBooleanByColumnName(cursor, Phone.IS_PRIMARY));
183
+ phoneObject.put("number", number);
184
+ phones.put(phoneObject);
185
+ }
186
+ break;
187
+ // Emails
188
+ case Email.CONTENT_ITEM_TYPE:
189
+ String address = getStringByColumnName(cursor, Email.ADDRESS);
190
+ Integer emailType = getIntByColumnName(cursor, Email.TYPE);
191
+ if (address != null && emailType != null) {
192
+ JSObject emailObject = new JSObject();
193
+ emailObject.put("type", Contacts.emailTypeMap.getKey(emailType));
194
+ emailObject.put("label", getStringByColumnName(cursor, Email.LABEL));
195
+ emailObject.put("isPrimary", getBooleanByColumnName(cursor, Email.IS_PRIMARY));
196
+ emailObject.put("address", address);
197
+ emails.put(emailObject);
198
+ }
199
+ break;
200
+ // URLs
201
+ case Website.CONTENT_ITEM_TYPE:
202
+ String url = getStringByColumnName(cursor, Website.URL);
203
+ urls.put(url);
204
+ break;
205
+ // Postal Addresses
206
+ case StructuredPostal.CONTENT_ITEM_TYPE:
207
+ Integer postalAddressType = getIntByColumnName(cursor, StructuredPostal.TYPE);
208
+ if (postalAddressType != null) {
209
+ JSObject postalAddressObject = new JSObject();
210
+ postalAddressObject.put("type", Contacts.postalAddressTypeMap.getKey(postalAddressType));
211
+ postalAddressObject.put("label", getStringByColumnName(cursor, StructuredPostal.LABEL));
212
+ postalAddressObject.put("isPrimary", getBooleanByColumnName(cursor, StructuredPostal.IS_PRIMARY));
213
+ postalAddressObject.put("formatted", getStringByColumnName(cursor, StructuredPostal.FORMATTED_ADDRESS));
214
+ postalAddressObject.put("street", getStringByColumnName(cursor, StructuredPostal.STREET));
215
+ postalAddressObject.put("neighborhood", getStringByColumnName(cursor, StructuredPostal.NEIGHBORHOOD));
216
+ postalAddressObject.put("city", getStringByColumnName(cursor, StructuredPostal.CITY));
217
+ postalAddressObject.put("region", getStringByColumnName(cursor, StructuredPostal.REGION));
218
+ postalAddressObject.put("postcode", getStringByColumnName(cursor, StructuredPostal.POSTCODE));
219
+ postalAddressObject.put("country", getStringByColumnName(cursor, StructuredPostal.COUNTRY));
220
+ postalAddresses.put(postalAddressObject);
221
+ }
222
+ break;
223
+ // Image
224
+ case Photo.CONTENT_ITEM_TYPE:
225
+ String base64String = getBase64ByColumnName(cursor, Photo.PHOTO);
226
+ if (base64String != null) {
227
+ image.put("base64String", base64String);
228
+ }
229
+ break;
230
+ }
231
+ }
232
+
233
+ public JSObject getJSObject() {
234
+ JSObject contact = new JSObject();
235
+
236
+ // Id
237
+ contact.put("contactId", contactId);
238
+
239
+ // Name
240
+ if (name.length() > 0) {
241
+ contact.put("name", name);
242
+ }
243
+
244
+ // Organization
245
+ if (organization.length() > 0) {
246
+ contact.put("organization", organization);
247
+ }
248
+
249
+ // Birthday
250
+ if (birthday.length() > 0) {
251
+ contact.put("birthday", birthday);
252
+ }
253
+
254
+ // Note
255
+ if (note != null) {
256
+ contact.put("note", note);
257
+ }
258
+
259
+ // Phones
260
+ if (phones.length() > 0) {
261
+ contact.put("phones", phones);
262
+ }
263
+
264
+ // Emails
265
+ if (emails.length() > 0) {
266
+ contact.put("emails", emails);
267
+ }
268
+
269
+ // URLs
270
+ if (urls.length() > 0) {
271
+ contact.put("urls", urls);
272
+ }
273
+
274
+ // Postal Addresses
275
+ if (postalAddresses.length() > 0) {
276
+ contact.put("postalAddresses", postalAddresses);
277
+ }
278
+
279
+ // Image
280
+ if (image.length() > 0) {
281
+ contact.put("image", image);
282
+ }
283
+
284
+ return contact;
285
+ }
286
+ }