react-native-contacts 7.0.8 → 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.
- package/android/build.gradle +28 -1
- package/android/src/main/java/com/rt2zz/reactnativecontacts/ContactsProvider.java +123 -129
- package/android/src/main/java/com/rt2zz/reactnativecontacts/ReactNativeContacts.java +32 -16
- package/android/src/newarch/com/rt2zz/reactnativecontacts/ContactsManager.java +1388 -0
- package/android/src/{main/java → oldarch}/com/rt2zz/reactnativecontacts/ContactsManager.java +100 -88
- package/index.d.ts +10 -10
- package/index.ts +113 -0
- package/ios/RCTContacts/RCTContacts.h +13 -1
- package/ios/RCTContacts/{RCTContacts.m → RCTContacts.mm} +519 -39
- package/package.json +19 -4
- package/react-native-contacts.podspec +27 -8
- package/src/NativeContacts.ts +27 -0
- package/type.ts +62 -0
- package/index.js +0 -2
|
@@ -0,0 +1,1388 @@
|
|
|
1
|
+
package com.rt2zz.reactnativecontacts;
|
|
2
|
+
|
|
3
|
+
import android.Manifest;
|
|
4
|
+
import android.app.Activity;
|
|
5
|
+
import android.content.ContentProviderOperation;
|
|
6
|
+
import android.content.ContentProviderResult;
|
|
7
|
+
import android.content.ContentResolver;
|
|
8
|
+
import android.content.ContentUris;
|
|
9
|
+
import android.content.ContentValues;
|
|
10
|
+
import android.content.Context;
|
|
11
|
+
import android.content.Intent;
|
|
12
|
+
import android.content.pm.PackageManager;
|
|
13
|
+
import android.content.res.AssetManager;
|
|
14
|
+
import android.graphics.Bitmap;
|
|
15
|
+
import android.graphics.BitmapFactory;
|
|
16
|
+
import android.net.Uri;
|
|
17
|
+
import android.os.AsyncTask;
|
|
18
|
+
import android.os.Bundle;
|
|
19
|
+
import android.provider.ContactsContract;
|
|
20
|
+
import android.provider.ContactsContract.CommonDataKinds;
|
|
21
|
+
import android.provider.ContactsContract.CommonDataKinds.Note;
|
|
22
|
+
import android.provider.ContactsContract.CommonDataKinds.Organization;
|
|
23
|
+
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
|
|
24
|
+
import android.provider.ContactsContract.RawContacts;
|
|
25
|
+
|
|
26
|
+
import androidx.annotation.NonNull;
|
|
27
|
+
import androidx.core.app.ActivityCompat;
|
|
28
|
+
|
|
29
|
+
import com.facebook.react.bridge.ActivityEventListener;
|
|
30
|
+
import com.facebook.react.bridge.Promise;
|
|
31
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
32
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
33
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
34
|
+
import com.facebook.react.bridge.WritableArray;
|
|
35
|
+
import com.facebook.react.bridge.WritableMap;
|
|
36
|
+
import com.rt2zz.reactnativecontacts.ContactsProvider;
|
|
37
|
+
import com.rt2zz.reactnativecontacts.NativeContactsSpec;
|
|
38
|
+
|
|
39
|
+
import java.io.ByteArrayOutputStream;
|
|
40
|
+
import java.io.FileNotFoundException;
|
|
41
|
+
import java.io.FileOutputStream;
|
|
42
|
+
import java.io.IOException;
|
|
43
|
+
import java.io.InputStream;
|
|
44
|
+
import java.io.OutputStream;
|
|
45
|
+
import java.util.ArrayList;
|
|
46
|
+
import java.util.Hashtable;
|
|
47
|
+
|
|
48
|
+
public class ContactsManager extends NativeContactsSpec implements ActivityEventListener {
|
|
49
|
+
|
|
50
|
+
private static final String PERMISSION_DENIED = "denied";
|
|
51
|
+
private static final String PERMISSION_AUTHORIZED = "authorized";
|
|
52
|
+
private static final String PERMISSION_READ_CONTACTS = Manifest.permission.READ_CONTACTS;
|
|
53
|
+
private static final int PERMISSION_REQUEST_CODE = 888;
|
|
54
|
+
|
|
55
|
+
private static final int REQUEST_OPEN_CONTACT_FORM = 52941;
|
|
56
|
+
private static final int REQUEST_OPEN_EXISTING_CONTACT = 52942;
|
|
57
|
+
|
|
58
|
+
private static Promise updateContactPromise;
|
|
59
|
+
private static Promise requestPromise;
|
|
60
|
+
|
|
61
|
+
public ContactsManager(ReactApplicationContext reactContext) {
|
|
62
|
+
super(reactContext);
|
|
63
|
+
reactContext.addActivityEventListener(this);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* Returns all contactable records on phone
|
|
68
|
+
* queries CommonDataKinds.Contactables to get phones and emails
|
|
69
|
+
*/
|
|
70
|
+
@Override
|
|
71
|
+
public void getAll(Promise promise) {
|
|
72
|
+
getAllContacts(promise);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Introduced for iOS compatibility. Same as getAll
|
|
77
|
+
*
|
|
78
|
+
* @param promise promise
|
|
79
|
+
*/
|
|
80
|
+
@Override
|
|
81
|
+
public void getAllWithoutPhotos(Promise promise) {
|
|
82
|
+
getAllContacts(promise);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Retrieves contacts.
|
|
87
|
+
* Uses raw URI when <code>rawUri</code> is <code>true</code>, makes assets copy
|
|
88
|
+
* otherwise.
|
|
89
|
+
*/
|
|
90
|
+
private void getAllContacts(final Promise promise) {
|
|
91
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
92
|
+
@Override
|
|
93
|
+
protected Void doInBackground(final Void... params) {
|
|
94
|
+
Context context = getReactApplicationContext();
|
|
95
|
+
ContentResolver cr = context.getContentResolver();
|
|
96
|
+
|
|
97
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
98
|
+
WritableArray contacts = contactsProvider.getContacts();
|
|
99
|
+
promise.resolve(contacts);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@Override
|
|
107
|
+
public void getCount(final Promise promise) {
|
|
108
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
109
|
+
@Override
|
|
110
|
+
protected Void doInBackground(final Void... params) {
|
|
111
|
+
Context context = getReactApplicationContext();
|
|
112
|
+
ContentResolver cr = context.getContentResolver();
|
|
113
|
+
|
|
114
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
115
|
+
try {
|
|
116
|
+
Integer contacts = contactsProvider.getContactsCount();
|
|
117
|
+
promise.resolve(contacts);
|
|
118
|
+
} catch (Exception e) {
|
|
119
|
+
promise.reject(e);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Retrieves contacts matching String.
|
|
131
|
+
* Uses raw URI when <code>rawUri</code> is <code>true</code>, makes assets copy
|
|
132
|
+
* otherwise.
|
|
133
|
+
*
|
|
134
|
+
* @param searchString String to match
|
|
135
|
+
*/
|
|
136
|
+
@Override
|
|
137
|
+
public void getContactsMatchingString(final String searchString, final Promise promise) {
|
|
138
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
139
|
+
@Override
|
|
140
|
+
protected Void doInBackground(final Void... params) {
|
|
141
|
+
Context context = getReactApplicationContext();
|
|
142
|
+
ContentResolver cr = context.getContentResolver();
|
|
143
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
144
|
+
WritableArray contacts = contactsProvider.getContactsMatchingString(searchString);
|
|
145
|
+
|
|
146
|
+
promise.resolve(contacts);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Retrieves contacts matching a phone number.
|
|
155
|
+
* Uses raw URI when <code>rawUri</code> is <code>true</code>, makes assets copy
|
|
156
|
+
* otherwise.
|
|
157
|
+
*
|
|
158
|
+
* @param phoneNumber phone number to match
|
|
159
|
+
*/
|
|
160
|
+
@Override
|
|
161
|
+
public void getContactsByPhoneNumber(final String phoneNumber, final Promise promise) {
|
|
162
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
163
|
+
@Override
|
|
164
|
+
protected Void doInBackground(final Void... params) {
|
|
165
|
+
Context context = getReactApplicationContext();
|
|
166
|
+
ContentResolver cr = context.getContentResolver();
|
|
167
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
168
|
+
WritableArray contacts = contactsProvider.getContactsByPhoneNumber(phoneNumber);
|
|
169
|
+
|
|
170
|
+
promise.resolve(contacts);
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Retrieves contacts matching an email address.
|
|
179
|
+
* Uses raw URI when <code>rawUri</code> is <code>true</code>, makes assets copy
|
|
180
|
+
* otherwise.
|
|
181
|
+
*
|
|
182
|
+
* @param emailAddress email address to match
|
|
183
|
+
*/
|
|
184
|
+
@Override
|
|
185
|
+
public void getContactsByEmailAddress(final String emailAddress, final Promise promise) {
|
|
186
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
187
|
+
@Override
|
|
188
|
+
protected Void doInBackground(final Void... params) {
|
|
189
|
+
Context context = getReactApplicationContext();
|
|
190
|
+
ContentResolver cr = context.getContentResolver();
|
|
191
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
192
|
+
WritableArray contacts = contactsProvider.getContactsByEmailAddress(emailAddress);
|
|
193
|
+
|
|
194
|
+
promise.resolve(contacts);
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Retrieves <code>thumbnailPath</code> for contact, or <code>null</code> if not
|
|
203
|
+
* available.
|
|
204
|
+
*
|
|
205
|
+
* @param contactId contact identifier, <code>recordID</code>
|
|
206
|
+
*/
|
|
207
|
+
@Override
|
|
208
|
+
public void getPhotoForId(final String contactId, final Promise promise) {
|
|
209
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
210
|
+
@Override
|
|
211
|
+
protected Void doInBackground(final Void... params) {
|
|
212
|
+
Context context = getReactApplicationContext();
|
|
213
|
+
ContentResolver cr = context.getContentResolver();
|
|
214
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
215
|
+
String photoUri = contactsProvider.getPhotoUriFromContactId(contactId);
|
|
216
|
+
|
|
217
|
+
promise.resolve(photoUri);
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Retrieves <code>contact</code> for contact, or <code>null</code> if not
|
|
226
|
+
* available.
|
|
227
|
+
*
|
|
228
|
+
* @param contactId contact identifier, <code>recordID</code>
|
|
229
|
+
*/
|
|
230
|
+
@Override
|
|
231
|
+
public void getContactById(final String contactId, final Promise promise) {
|
|
232
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
233
|
+
@Override
|
|
234
|
+
protected Void doInBackground(final Void... params) {
|
|
235
|
+
Context context = getReactApplicationContext();
|
|
236
|
+
ContentResolver cr = context.getContentResolver();
|
|
237
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
238
|
+
WritableMap contact = contactsProvider.getContactById(contactId);
|
|
239
|
+
|
|
240
|
+
promise.resolve(contact);
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@Override
|
|
248
|
+
public void writePhotoToPath(final String contactId, final String file, final Promise promise) {
|
|
249
|
+
AsyncTask<Void, Void, Void> myAsyncTask = new AsyncTask<Void, Void, Void>() {
|
|
250
|
+
@Override
|
|
251
|
+
protected Void doInBackground(final Void... params) {
|
|
252
|
+
Context context = getReactApplicationContext();
|
|
253
|
+
ContentResolver cr = context.getContentResolver();
|
|
254
|
+
|
|
255
|
+
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
|
|
256
|
+
InputStream inputStream = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
|
|
257
|
+
OutputStream outputStream = null;
|
|
258
|
+
try {
|
|
259
|
+
outputStream = new FileOutputStream(file);
|
|
260
|
+
BitmapFactory.decodeStream(inputStream).compress(Bitmap.CompressFormat.PNG, 100, outputStream);
|
|
261
|
+
promise.resolve(true);
|
|
262
|
+
} catch (FileNotFoundException e) {
|
|
263
|
+
promise.reject(e.toString());
|
|
264
|
+
} finally {
|
|
265
|
+
try {
|
|
266
|
+
outputStream.close();
|
|
267
|
+
} catch (IOException e) {
|
|
268
|
+
e.printStackTrace();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
inputStream.close();
|
|
273
|
+
} catch (IOException e) {
|
|
274
|
+
e.printStackTrace();
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
myAsyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private Bitmap getThumbnailBitmap(String thumbnailPath) {
|
|
283
|
+
// Thumbnail from absolute path
|
|
284
|
+
Bitmap photo = BitmapFactory.decodeFile(thumbnailPath);
|
|
285
|
+
|
|
286
|
+
if (photo == null) {
|
|
287
|
+
// Try to find the thumbnail from assets
|
|
288
|
+
AssetManager assetManager = getReactApplicationContext().getAssets();
|
|
289
|
+
InputStream inputStream = null;
|
|
290
|
+
try {
|
|
291
|
+
inputStream = assetManager.open(thumbnailPath);
|
|
292
|
+
photo = BitmapFactory.decodeStream(inputStream);
|
|
293
|
+
inputStream.close();
|
|
294
|
+
} catch (IOException e) {
|
|
295
|
+
e.printStackTrace();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return photo;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/*
|
|
303
|
+
* Start open contact form
|
|
304
|
+
*/
|
|
305
|
+
@Override
|
|
306
|
+
public void openContactForm(ReadableMap contact, Promise promise) {
|
|
307
|
+
|
|
308
|
+
String givenName = contact.hasKey("givenName") ? contact.getString("givenName") : null;
|
|
309
|
+
String middleName = contact.hasKey("middleName") ? contact.getString("middleName") : null;
|
|
310
|
+
String displayName = contact.hasKey("displayName") ? contact.getString("displayName") : null;
|
|
311
|
+
String familyName = contact.hasKey("familyName") ? contact.getString("familyName") : null;
|
|
312
|
+
String prefix = contact.hasKey("prefix") ? contact.getString("prefix") : null;
|
|
313
|
+
String suffix = contact.hasKey("suffix") ? contact.getString("suffix") : null;
|
|
314
|
+
String company = contact.hasKey("company") ? contact.getString("company") : null;
|
|
315
|
+
String jobTitle = contact.hasKey("jobTitle") ? contact.getString("jobTitle") : null;
|
|
316
|
+
String department = contact.hasKey("department") ? contact.getString("department") : null;
|
|
317
|
+
String note = contact.hasKey("note") ? contact.getString("note") : null;
|
|
318
|
+
String thumbnailPath = contact.hasKey("thumbnailPath") ? contact.getString("thumbnailPath") : null;
|
|
319
|
+
|
|
320
|
+
ReadableArray phoneNumbers = contact.hasKey("phoneNumbers") ? contact.getArray("phoneNumbers") : null;
|
|
321
|
+
int numOfPhones = 0;
|
|
322
|
+
String[] phones = null;
|
|
323
|
+
String[] phonesLabels = null;
|
|
324
|
+
Integer[] phonesLabelsTypes = null;
|
|
325
|
+
if (phoneNumbers != null) {
|
|
326
|
+
numOfPhones = phoneNumbers.size();
|
|
327
|
+
phones = new String[numOfPhones];
|
|
328
|
+
phonesLabels = new String[numOfPhones];
|
|
329
|
+
phonesLabelsTypes = new Integer[numOfPhones];
|
|
330
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
331
|
+
phones[i] = phoneNumbers.getMap(i).getString("number");
|
|
332
|
+
String label = phoneNumbers.getMap(i).getString("label");
|
|
333
|
+
phonesLabels[i] = label;
|
|
334
|
+
phonesLabelsTypes[i] = mapStringToPhoneType(label);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
ReadableArray urlAddresses = contact.hasKey("urlAddresses") ? contact.getArray("urlAddresses") : null;
|
|
339
|
+
int numOfUrls = 0;
|
|
340
|
+
String[] urls = null;
|
|
341
|
+
if (urlAddresses != null) {
|
|
342
|
+
numOfUrls = urlAddresses.size();
|
|
343
|
+
urls = new String[numOfUrls];
|
|
344
|
+
for (int i = 0; i < numOfUrls; i++) {
|
|
345
|
+
urls[i] = urlAddresses.getMap(i).getString("url");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
ReadableArray emailAddresses = contact.hasKey("emailAddresses") ? contact.getArray("emailAddresses") : null;
|
|
350
|
+
int numOfEmails = 0;
|
|
351
|
+
String[] emails = null;
|
|
352
|
+
Integer[] emailsLabels = null;
|
|
353
|
+
if (emailAddresses != null) {
|
|
354
|
+
numOfEmails = emailAddresses.size();
|
|
355
|
+
emails = new String[numOfEmails];
|
|
356
|
+
emailsLabels = new Integer[numOfEmails];
|
|
357
|
+
for (int i = 0; i < numOfEmails; i++) {
|
|
358
|
+
emails[i] = emailAddresses.getMap(i).getString("email");
|
|
359
|
+
String label = emailAddresses.getMap(i).getString("label");
|
|
360
|
+
emailsLabels[i] = mapStringToEmailType(label);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
ReadableArray postalAddresses = contact.hasKey("postalAddresses") ? contact.getArray("postalAddresses") : null;
|
|
365
|
+
int numOfPostalAddresses = 0;
|
|
366
|
+
String[] postalAddressesStreet = null;
|
|
367
|
+
String[] postalAddressesCity = null;
|
|
368
|
+
String[] postalAddressesState = null;
|
|
369
|
+
String[] postalAddressesRegion = null;
|
|
370
|
+
String[] postalAddressesPostCode = null;
|
|
371
|
+
String[] postalAddressesCountry = null;
|
|
372
|
+
String[] postalAddressesFormattedAddress = null;
|
|
373
|
+
String[] postalAddressesLabel = null;
|
|
374
|
+
Integer[] postalAddressesType = null;
|
|
375
|
+
|
|
376
|
+
if (postalAddresses != null) {
|
|
377
|
+
numOfPostalAddresses = postalAddresses.size();
|
|
378
|
+
postalAddressesStreet = new String[numOfPostalAddresses];
|
|
379
|
+
postalAddressesCity = new String[numOfPostalAddresses];
|
|
380
|
+
postalAddressesState = new String[numOfPostalAddresses];
|
|
381
|
+
postalAddressesRegion = new String[numOfPostalAddresses];
|
|
382
|
+
postalAddressesPostCode = new String[numOfPostalAddresses];
|
|
383
|
+
postalAddressesCountry = new String[numOfPostalAddresses];
|
|
384
|
+
postalAddressesFormattedAddress = new String[numOfPostalAddresses];
|
|
385
|
+
postalAddressesLabel = new String[numOfPostalAddresses];
|
|
386
|
+
postalAddressesType = new Integer[numOfPostalAddresses];
|
|
387
|
+
for (int i = 0; i < numOfPostalAddresses; i++) {
|
|
388
|
+
postalAddressesStreet[i] = postalAddresses.getMap(i).getString("street");
|
|
389
|
+
postalAddressesCity[i] = postalAddresses.getMap(i).getString("city");
|
|
390
|
+
postalAddressesState[i] = postalAddresses.getMap(i).getString("state");
|
|
391
|
+
postalAddressesRegion[i] = postalAddresses.getMap(i).getString("region");
|
|
392
|
+
postalAddressesPostCode[i] = postalAddresses.getMap(i).getString("postCode");
|
|
393
|
+
postalAddressesCountry[i] = postalAddresses.getMap(i).getString("country");
|
|
394
|
+
postalAddressesFormattedAddress[i] = postalAddresses.getMap(i).getString("formattedAddress");
|
|
395
|
+
postalAddressesLabel[i] = postalAddresses.getMap(i).getString("label");
|
|
396
|
+
postalAddressesType[i] = mapStringToPostalAddressType(postalAddresses.getMap(i).getString("label"));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
ReadableArray imAddresses = contact.hasKey("imAddresses") ? contact.getArray("imAddresses") : null;
|
|
401
|
+
int numOfIMAddresses = 0;
|
|
402
|
+
String[] imAccounts = null;
|
|
403
|
+
String[] imProtocols = null;
|
|
404
|
+
if (imAddresses != null) {
|
|
405
|
+
numOfIMAddresses = imAddresses.size();
|
|
406
|
+
imAccounts = new String[numOfIMAddresses];
|
|
407
|
+
imProtocols = new String[numOfIMAddresses];
|
|
408
|
+
for (int i = 0; i < numOfIMAddresses; i++) {
|
|
409
|
+
imAccounts[i] = imAddresses.getMap(i).getString("username");
|
|
410
|
+
imProtocols[i] = imAddresses.getMap(i).getString("service");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
ArrayList<ContentValues> contactData = new ArrayList<>();
|
|
415
|
+
|
|
416
|
+
ContentValues name = new ContentValues();
|
|
417
|
+
name.put(ContactsContract.Contacts.Data.MIMETYPE, CommonDataKinds.Identity.CONTENT_ITEM_TYPE);
|
|
418
|
+
name.put(StructuredName.GIVEN_NAME, givenName);
|
|
419
|
+
name.put(StructuredName.FAMILY_NAME, familyName);
|
|
420
|
+
name.put(StructuredName.MIDDLE_NAME, middleName);
|
|
421
|
+
name.put(StructuredName.PREFIX, prefix);
|
|
422
|
+
name.put(StructuredName.SUFFIX, suffix);
|
|
423
|
+
contactData.add(name);
|
|
424
|
+
|
|
425
|
+
ContentValues organization = new ContentValues();
|
|
426
|
+
organization.put(ContactsContract.Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
|
|
427
|
+
organization.put(Organization.COMPANY, company);
|
|
428
|
+
organization.put(Organization.TITLE, jobTitle);
|
|
429
|
+
organization.put(Organization.DEPARTMENT, department);
|
|
430
|
+
contactData.add(organization);
|
|
431
|
+
|
|
432
|
+
for (int i = 0; i < numOfUrls; i++) {
|
|
433
|
+
ContentValues url = new ContentValues();
|
|
434
|
+
url.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Website.CONTENT_ITEM_TYPE);
|
|
435
|
+
url.put(CommonDataKinds.Website.URL, urls[i]);
|
|
436
|
+
contactData.add(url);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
for (int i = 0; i < numOfEmails; i++) {
|
|
440
|
+
ContentValues email = new ContentValues();
|
|
441
|
+
email.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE);
|
|
442
|
+
email.put(CommonDataKinds.Email.TYPE, emailsLabels[i]);
|
|
443
|
+
email.put(CommonDataKinds.Email.ADDRESS, emails[i]);
|
|
444
|
+
contactData.add(email);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
448
|
+
ContentValues phone = new ContentValues();
|
|
449
|
+
phone.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
|
|
450
|
+
phone.put(CommonDataKinds.Phone.TYPE, phonesLabelsTypes[i]);
|
|
451
|
+
phone.put(CommonDataKinds.Phone.LABEL, phonesLabels[i]);
|
|
452
|
+
phone.put(CommonDataKinds.Phone.NUMBER, phones[i]);
|
|
453
|
+
|
|
454
|
+
contactData.add(phone);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
for (int i = 0; i < numOfPostalAddresses; i++) {
|
|
458
|
+
ContentValues structuredPostal = new ContentValues();
|
|
459
|
+
structuredPostal.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
|
|
460
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.STREET, postalAddressesStreet[i]);
|
|
461
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.CITY, postalAddressesCity[i]);
|
|
462
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.REGION, postalAddressesRegion[i]);
|
|
463
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.COUNTRY, postalAddressesCountry[i]);
|
|
464
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.POSTCODE, postalAddressesPostCode[i]);
|
|
465
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS,
|
|
466
|
+
postalAddressesFormattedAddress[i]);
|
|
467
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.LABEL, postalAddressesLabel[i]);
|
|
468
|
+
structuredPostal.put(CommonDataKinds.StructuredPostal.TYPE, postalAddressesType[i]);
|
|
469
|
+
// No state column in StructuredPostal
|
|
470
|
+
// structuredPostal.put(CommonDataKinds.StructuredPostal.???,
|
|
471
|
+
// postalAddressesState[i]);
|
|
472
|
+
contactData.add(structuredPostal);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
for (int i = 0; i < numOfIMAddresses; i++) {
|
|
476
|
+
ContentValues imAddress = new ContentValues();
|
|
477
|
+
imAddress.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Im.CONTENT_ITEM_TYPE);
|
|
478
|
+
imAddress.put(CommonDataKinds.Im.DATA, imAccounts[i]);
|
|
479
|
+
imAddress.put(CommonDataKinds.Im.TYPE, CommonDataKinds.Im.TYPE_HOME);
|
|
480
|
+
imAddress.put(CommonDataKinds.Im.PROTOCOL, CommonDataKinds.Im.PROTOCOL_CUSTOM);
|
|
481
|
+
imAddress.put(CommonDataKinds.Im.CUSTOM_PROTOCOL, imProtocols[i]);
|
|
482
|
+
contactData.add(imAddress);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (note != null) {
|
|
486
|
+
ContentValues structuredNote = new ContentValues();
|
|
487
|
+
structuredNote.put(ContactsContract.Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
|
|
488
|
+
structuredNote.put(Note.NOTE, note);
|
|
489
|
+
contactData.add(structuredNote);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (thumbnailPath != null && !thumbnailPath.isEmpty()) {
|
|
493
|
+
Bitmap photo = getThumbnailBitmap(thumbnailPath);
|
|
494
|
+
|
|
495
|
+
if (photo != null) {
|
|
496
|
+
ContentValues thumbnail = new ContentValues();
|
|
497
|
+
thumbnail.put(ContactsContract.Data.RAW_CONTACT_ID, 0);
|
|
498
|
+
thumbnail.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
|
|
499
|
+
thumbnail.put(CommonDataKinds.Photo.PHOTO, toByteArray(photo));
|
|
500
|
+
thumbnail.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
|
|
501
|
+
contactData.add(thumbnail);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
Intent intent = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
|
|
506
|
+
intent.putExtra(ContactsContract.Intents.Insert.NAME, displayName);
|
|
507
|
+
intent.putExtra("finishActivityOnSaveCompleted", true);
|
|
508
|
+
intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);
|
|
509
|
+
|
|
510
|
+
updateContactPromise = promise;
|
|
511
|
+
getReactApplicationContext().startActivityForResult(intent, REQUEST_OPEN_CONTACT_FORM, Bundle.EMPTY);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/*
|
|
515
|
+
* Open contact in native app
|
|
516
|
+
*/
|
|
517
|
+
@Override
|
|
518
|
+
public void openExistingContact(ReadableMap contact, Promise promise) {
|
|
519
|
+
|
|
520
|
+
String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
|
|
521
|
+
|
|
522
|
+
try {
|
|
523
|
+
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, recordID);
|
|
524
|
+
Intent intent = new Intent(Intent.ACTION_EDIT);
|
|
525
|
+
intent.setDataAndType(uri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
|
526
|
+
intent.putExtra("finishActivityOnSaveCompleted", true);
|
|
527
|
+
|
|
528
|
+
updateContactPromise = promise;
|
|
529
|
+
getReactApplicationContext().startActivityForResult(intent, REQUEST_OPEN_EXISTING_CONTACT, Bundle.EMPTY);
|
|
530
|
+
|
|
531
|
+
} catch (Exception e) {
|
|
532
|
+
promise.reject(e.toString());
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/*
|
|
537
|
+
* View contact in native app
|
|
538
|
+
*/
|
|
539
|
+
@Override
|
|
540
|
+
public void viewExistingContact(ReadableMap contact, Promise promise) {
|
|
541
|
+
|
|
542
|
+
String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, recordID);
|
|
546
|
+
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
547
|
+
intent.setDataAndType(uri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
|
548
|
+
intent.putExtra("finishActivityOnSaveCompleted", true);
|
|
549
|
+
|
|
550
|
+
updateContactPromise = promise;
|
|
551
|
+
getReactApplicationContext().startActivityForResult(intent, REQUEST_OPEN_EXISTING_CONTACT, Bundle.EMPTY);
|
|
552
|
+
|
|
553
|
+
} catch (Exception e) {
|
|
554
|
+
promise.reject(e.toString());
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/*
|
|
559
|
+
* Edit contact in native app
|
|
560
|
+
*/
|
|
561
|
+
@Override
|
|
562
|
+
public void editExistingContact(ReadableMap contact, Promise promise) {
|
|
563
|
+
|
|
564
|
+
String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, recordID);
|
|
568
|
+
|
|
569
|
+
ReadableArray phoneNumbers = contact.hasKey("phoneNumbers") ? contact.getArray("phoneNumbers") : null;
|
|
570
|
+
int numOfPhones = 0;
|
|
571
|
+
String[] phones = null;
|
|
572
|
+
Integer[] phonesLabels = null;
|
|
573
|
+
if (phoneNumbers != null) {
|
|
574
|
+
numOfPhones = phoneNumbers.size();
|
|
575
|
+
phones = new String[numOfPhones];
|
|
576
|
+
phonesLabels = new Integer[numOfPhones];
|
|
577
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
578
|
+
phones[i] = phoneNumbers.getMap(i).getString("number");
|
|
579
|
+
String label = phoneNumbers.getMap(i).getString("label");
|
|
580
|
+
phonesLabels[i] = mapStringToPhoneType(label);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
ArrayList<ContentValues> contactData = new ArrayList<>();
|
|
585
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
586
|
+
ContentValues phone = new ContentValues();
|
|
587
|
+
phone.put(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
|
|
588
|
+
phone.put(CommonDataKinds.Phone.TYPE, phonesLabels[i]);
|
|
589
|
+
phone.put(CommonDataKinds.Phone.NUMBER, phones[i]);
|
|
590
|
+
contactData.add(phone);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
Intent intent = new Intent(Intent.ACTION_EDIT);
|
|
594
|
+
intent.setDataAndType(uri, ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
|
595
|
+
intent.putExtra("finishActivityOnSaveCompleted", true);
|
|
596
|
+
intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);
|
|
597
|
+
|
|
598
|
+
updateContactPromise = promise;
|
|
599
|
+
getReactApplicationContext().startActivityForResult(intent, REQUEST_OPEN_EXISTING_CONTACT, Bundle.EMPTY);
|
|
600
|
+
|
|
601
|
+
} catch (Exception e) {
|
|
602
|
+
promise.reject(e.toString());
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/*
|
|
607
|
+
* Adds contact to phone's addressbook
|
|
608
|
+
*/
|
|
609
|
+
@Override
|
|
610
|
+
public void addContact(ReadableMap contact, Promise promise) {
|
|
611
|
+
if (contact == null) {
|
|
612
|
+
promise.reject("New contact cannot be null.");
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
String givenName = contact.hasKey("givenName") ? contact.getString("givenName") : null;
|
|
616
|
+
String middleName = contact.hasKey("middleName") ? contact.getString("middleName") : null;
|
|
617
|
+
String familyName = contact.hasKey("familyName") ? contact.getString("familyName") : null;
|
|
618
|
+
String prefix = contact.hasKey("prefix") ? contact.getString("prefix") : null;
|
|
619
|
+
String suffix = contact.hasKey("suffix") ? contact.getString("suffix") : null;
|
|
620
|
+
String company = contact.hasKey("company") ? contact.getString("company") : null;
|
|
621
|
+
String jobTitle = contact.hasKey("jobTitle") ? contact.getString("jobTitle") : null;
|
|
622
|
+
String department = contact.hasKey("department") ? contact.getString("department") : null;
|
|
623
|
+
String note = contact.hasKey("note") ? contact.getString("note") : null;
|
|
624
|
+
String thumbnailPath = contact.hasKey("thumbnailPath") ? contact.getString("thumbnailPath") : null;
|
|
625
|
+
|
|
626
|
+
ReadableArray phoneNumbers = contact.hasKey("phoneNumbers") ? contact.getArray("phoneNumbers") : null;
|
|
627
|
+
int numOfPhones = 0;
|
|
628
|
+
String[] phones = null;
|
|
629
|
+
Integer[] phonesTypes = null;
|
|
630
|
+
String[] phonesLabels = null;
|
|
631
|
+
if (phoneNumbers != null) {
|
|
632
|
+
numOfPhones = phoneNumbers.size();
|
|
633
|
+
phones = new String[numOfPhones];
|
|
634
|
+
phonesTypes = new Integer[numOfPhones];
|
|
635
|
+
phonesLabels = new String[numOfPhones];
|
|
636
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
637
|
+
phones[i] = phoneNumbers.getMap(i).getString("number");
|
|
638
|
+
String label = phoneNumbers.getMap(i).getString("label");
|
|
639
|
+
phonesTypes[i] = mapStringToPhoneType(label);
|
|
640
|
+
phonesLabels[i] = label;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
ReadableArray urlAddresses = contact.hasKey("urlAddresses") ? contact.getArray("urlAddresses") : null;
|
|
645
|
+
int numOfUrls = 0;
|
|
646
|
+
String[] urls = null;
|
|
647
|
+
if (urlAddresses != null) {
|
|
648
|
+
numOfUrls = urlAddresses.size();
|
|
649
|
+
urls = new String[numOfUrls];
|
|
650
|
+
for (int i = 0; i < numOfUrls; i++) {
|
|
651
|
+
urls[i] = urlAddresses.getMap(i).getString("url");
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
ReadableArray emailAddresses = contact.hasKey("emailAddresses") ? contact.getArray("emailAddresses") : null;
|
|
656
|
+
int numOfEmails = 0;
|
|
657
|
+
String[] emails = null;
|
|
658
|
+
Integer[] emailsTypes = null;
|
|
659
|
+
String[] emailsLabels = null;
|
|
660
|
+
if (emailAddresses != null) {
|
|
661
|
+
numOfEmails = emailAddresses.size();
|
|
662
|
+
emails = new String[numOfEmails];
|
|
663
|
+
emailsTypes = new Integer[numOfEmails];
|
|
664
|
+
emailsLabels = new String[numOfEmails];
|
|
665
|
+
for (int i = 0; i < numOfEmails; i++) {
|
|
666
|
+
emails[i] = emailAddresses.getMap(i).getString("email");
|
|
667
|
+
String label = emailAddresses.getMap(i).getString("label");
|
|
668
|
+
emailsTypes[i] = mapStringToEmailType(label);
|
|
669
|
+
emailsLabels[i] = label;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
ReadableArray imAddresses = contact.hasKey("imAddresses") ? contact.getArray("imAddresses") : null;
|
|
674
|
+
int numOfIMAddresses = 0;
|
|
675
|
+
String[] imAccounts = null;
|
|
676
|
+
String[] imProtocols = null;
|
|
677
|
+
if (imAddresses != null) {
|
|
678
|
+
numOfIMAddresses = imAddresses.size();
|
|
679
|
+
imAccounts = new String[numOfIMAddresses];
|
|
680
|
+
imProtocols = new String[numOfIMAddresses];
|
|
681
|
+
for (int i = 0; i < numOfIMAddresses; i++) {
|
|
682
|
+
imAccounts[i] = imAddresses.getMap(i).getString("username");
|
|
683
|
+
imProtocols[i] = imAddresses.getMap(i).getString("service");
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
|
|
688
|
+
|
|
689
|
+
ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
|
|
690
|
+
.withValue(RawContacts.ACCOUNT_TYPE, null)
|
|
691
|
+
.withValue(RawContacts.ACCOUNT_NAME, null);
|
|
692
|
+
ops.add(op.build());
|
|
693
|
+
|
|
694
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
695
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
696
|
+
.withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
|
|
697
|
+
// .withValue(StructuredName.DISPLAY_NAME, name)
|
|
698
|
+
.withValue(StructuredName.GIVEN_NAME, givenName)
|
|
699
|
+
.withValue(StructuredName.MIDDLE_NAME, middleName)
|
|
700
|
+
.withValue(StructuredName.FAMILY_NAME, familyName)
|
|
701
|
+
.withValue(StructuredName.PREFIX, prefix)
|
|
702
|
+
.withValue(StructuredName.SUFFIX, suffix);
|
|
703
|
+
ops.add(op.build());
|
|
704
|
+
|
|
705
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
706
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
707
|
+
.withValue(ContactsContract.Data.MIMETYPE, Note.CONTENT_ITEM_TYPE)
|
|
708
|
+
.withValue(Note.NOTE, note);
|
|
709
|
+
ops.add(op.build());
|
|
710
|
+
|
|
711
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
712
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
713
|
+
.withValue(ContactsContract.Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE)
|
|
714
|
+
.withValue(Organization.COMPANY, company)
|
|
715
|
+
.withValue(Organization.TITLE, jobTitle)
|
|
716
|
+
.withValue(Organization.DEPARTMENT, department);
|
|
717
|
+
ops.add(op.build());
|
|
718
|
+
|
|
719
|
+
// TODO not sure where to allow yields
|
|
720
|
+
op.withYieldAllowed(true);
|
|
721
|
+
|
|
722
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
723
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
724
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
725
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
|
726
|
+
.withValue(CommonDataKinds.Phone.NUMBER, phones[i])
|
|
727
|
+
.withValue(CommonDataKinds.Phone.TYPE, phonesTypes[i])
|
|
728
|
+
.withValue(CommonDataKinds.Phone.LABEL, phonesLabels[i]);
|
|
729
|
+
ops.add(op.build());
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
for (int i = 0; i < numOfUrls; i++) {
|
|
733
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
734
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
735
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Website.CONTENT_ITEM_TYPE)
|
|
736
|
+
.withValue(CommonDataKinds.Website.URL, urls[i]);
|
|
737
|
+
ops.add(op.build());
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
for (int i = 0; i < numOfEmails; i++) {
|
|
741
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
742
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
743
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|
|
744
|
+
.withValue(CommonDataKinds.Email.ADDRESS, emails[i])
|
|
745
|
+
.withValue(CommonDataKinds.Email.TYPE, emailsTypes[i])
|
|
746
|
+
.withValue(CommonDataKinds.Email.LABEL, emailsLabels[i]);
|
|
747
|
+
ops.add(op.build());
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (thumbnailPath != null && !thumbnailPath.isEmpty()) {
|
|
751
|
+
Bitmap photo = getThumbnailBitmap(thumbnailPath);
|
|
752
|
+
|
|
753
|
+
if (photo != null) {
|
|
754
|
+
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
755
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
756
|
+
.withValue(ContactsContract.Data.MIMETYPE,
|
|
757
|
+
CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
|
|
758
|
+
.withValue(CommonDataKinds.Photo.PHOTO, toByteArray(photo))
|
|
759
|
+
.build());
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
ReadableArray postalAddresses = contact.hasKey("postalAddresses") ? contact.getArray("postalAddresses") : null;
|
|
764
|
+
if (postalAddresses != null) {
|
|
765
|
+
for (int i = 0; i < postalAddresses.size(); i++) {
|
|
766
|
+
ReadableMap address = postalAddresses.getMap(i);
|
|
767
|
+
|
|
768
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
769
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
770
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
|
|
771
|
+
.withValue(CommonDataKinds.StructuredPostal.TYPE,
|
|
772
|
+
mapStringToPostalAddressType(address.getString("label")))
|
|
773
|
+
.withValue(CommonDataKinds.StructuredPostal.LABEL, address.getString("label"))
|
|
774
|
+
.withValue(CommonDataKinds.StructuredPostal.STREET, address.getString("street"))
|
|
775
|
+
.withValue(CommonDataKinds.StructuredPostal.CITY, address.getString("city"))
|
|
776
|
+
.withValue(CommonDataKinds.StructuredPostal.REGION, address.getString("state"))
|
|
777
|
+
.withValue(CommonDataKinds.StructuredPostal.POSTCODE, address.getString("postCode"))
|
|
778
|
+
.withValue(CommonDataKinds.StructuredPostal.COUNTRY, address.getString("country"));
|
|
779
|
+
|
|
780
|
+
ops.add(op.build());
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
for (int i = 0; i < numOfIMAddresses; i++) {
|
|
785
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
786
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
787
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Im.CONTENT_ITEM_TYPE)
|
|
788
|
+
.withValue(CommonDataKinds.Im.DATA, imAccounts[i])
|
|
789
|
+
.withValue(CommonDataKinds.Im.TYPE, CommonDataKinds.Im.TYPE_HOME)
|
|
790
|
+
.withValue(CommonDataKinds.Im.PROTOCOL, CommonDataKinds.Im.PROTOCOL_CUSTOM)
|
|
791
|
+
.withValue(CommonDataKinds.Im.CUSTOM_PROTOCOL, imProtocols[i]);
|
|
792
|
+
ops.add(op.build());
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
Context ctx = getReactApplicationContext();
|
|
796
|
+
try {
|
|
797
|
+
ContentResolver cr = ctx.getContentResolver();
|
|
798
|
+
ContentProviderResult[] result = cr.applyBatch(ContactsContract.AUTHORITY, ops);
|
|
799
|
+
|
|
800
|
+
if (result != null && result.length > 0) {
|
|
801
|
+
|
|
802
|
+
String rawId = String.valueOf(ContentUris.parseId(result[0].uri));
|
|
803
|
+
|
|
804
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
805
|
+
WritableMap newlyAddedContact = contactsProvider.getContactByRawId(rawId);
|
|
806
|
+
|
|
807
|
+
promise.resolve(newlyAddedContact); // success
|
|
808
|
+
}
|
|
809
|
+
} catch (Exception e) {
|
|
810
|
+
promise.reject(e.toString());
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
public byte[] toByteArray(Bitmap bitmap) {
|
|
815
|
+
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
816
|
+
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream);
|
|
817
|
+
return stream.toByteArray();
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/*
|
|
821
|
+
* Update contact to phone's addressbook
|
|
822
|
+
*/
|
|
823
|
+
@Override
|
|
824
|
+
public void updateContact(ReadableMap contact, Promise promise) {
|
|
825
|
+
|
|
826
|
+
String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
|
|
827
|
+
String rawContactId = contact.hasKey("rawContactId") ? contact.getString("rawContactId") : null;
|
|
828
|
+
|
|
829
|
+
if (rawContactId == null || recordID == null) {
|
|
830
|
+
promise.reject("Invalid recordId or rawContactId");
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
String givenName = contact.hasKey("givenName") ? contact.getString("givenName") : null;
|
|
835
|
+
String middleName = contact.hasKey("middleName") ? contact.getString("middleName") : null;
|
|
836
|
+
String familyName = contact.hasKey("familyName") ? contact.getString("familyName") : null;
|
|
837
|
+
String prefix = contact.hasKey("prefix") ? contact.getString("prefix") : null;
|
|
838
|
+
String suffix = contact.hasKey("suffix") ? contact.getString("suffix") : null;
|
|
839
|
+
String company = contact.hasKey("company") ? contact.getString("company") : null;
|
|
840
|
+
String jobTitle = contact.hasKey("jobTitle") ? contact.getString("jobTitle") : null;
|
|
841
|
+
String department = contact.hasKey("department") ? contact.getString("department") : null;
|
|
842
|
+
String note = contact.hasKey("note") ? contact.getString("note") : null;
|
|
843
|
+
String thumbnailPath = contact.hasKey("thumbnailPath") ? contact.getString("thumbnailPath") : null;
|
|
844
|
+
|
|
845
|
+
ReadableArray phoneNumbers = contact.hasKey("phoneNumbers") ? contact.getArray("phoneNumbers") : null;
|
|
846
|
+
int numOfPhones = 0;
|
|
847
|
+
String[] phones = null;
|
|
848
|
+
Integer[] phonesTypes = null;
|
|
849
|
+
String[] phonesLabels = null;
|
|
850
|
+
String[] phoneIds = null;
|
|
851
|
+
if (phoneNumbers != null) {
|
|
852
|
+
numOfPhones = phoneNumbers.size();
|
|
853
|
+
phones = new String[numOfPhones];
|
|
854
|
+
phonesTypes = new Integer[numOfPhones];
|
|
855
|
+
phonesLabels = new String[numOfPhones];
|
|
856
|
+
phoneIds = new String[numOfPhones];
|
|
857
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
858
|
+
ReadableMap phoneMap = phoneNumbers.getMap(i);
|
|
859
|
+
String phoneNumber = phoneMap.getString("number");
|
|
860
|
+
String phoneLabel = phoneMap.getString("label");
|
|
861
|
+
String phoneId = phoneMap.hasKey("id") ? phoneMap.getString("id") : null;
|
|
862
|
+
phones[i] = phoneNumber;
|
|
863
|
+
phonesTypes[i] = mapStringToPhoneType(phoneLabel);
|
|
864
|
+
phonesLabels[i] = phoneLabel;
|
|
865
|
+
phoneIds[i] = phoneId;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
ReadableArray urlAddresses = contact.hasKey("urlAddresses") ? contact.getArray("urlAddresses") : null;
|
|
870
|
+
int numOfUrls = 0;
|
|
871
|
+
String[] urls = null;
|
|
872
|
+
String[] urlIds = null;
|
|
873
|
+
|
|
874
|
+
if (urlAddresses != null) {
|
|
875
|
+
numOfUrls = urlAddresses.size();
|
|
876
|
+
urls = new String[numOfUrls];
|
|
877
|
+
urlIds = new String[numOfUrls];
|
|
878
|
+
for (int i = 0; i < numOfUrls; i++) {
|
|
879
|
+
ReadableMap urlMap = urlAddresses.getMap(i);
|
|
880
|
+
urls[i] = urlMap.getString("url");
|
|
881
|
+
urlIds[i] = urlMap.hasKey("id") ? urlMap.getString("id") : null;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
ReadableArray emailAddresses = contact.hasKey("emailAddresses") ? contact.getArray("emailAddresses") : null;
|
|
886
|
+
int numOfEmails = 0;
|
|
887
|
+
String[] emails = null;
|
|
888
|
+
Integer[] emailsTypes = null;
|
|
889
|
+
String[] emailsLabels = null;
|
|
890
|
+
String[] emailIds = null;
|
|
891
|
+
|
|
892
|
+
if (emailAddresses != null) {
|
|
893
|
+
numOfEmails = emailAddresses.size();
|
|
894
|
+
emails = new String[numOfEmails];
|
|
895
|
+
emailIds = new String[numOfEmails];
|
|
896
|
+
emailsTypes = new Integer[numOfEmails];
|
|
897
|
+
emailsLabels = new String[numOfEmails];
|
|
898
|
+
for (int i = 0; i < numOfEmails; i++) {
|
|
899
|
+
ReadableMap emailMap = emailAddresses.getMap(i);
|
|
900
|
+
emails[i] = emailMap.getString("email");
|
|
901
|
+
String label = emailMap.getString("label");
|
|
902
|
+
emailsTypes[i] = mapStringToEmailType(label);
|
|
903
|
+
emailsLabels[i] = label;
|
|
904
|
+
emailIds[i] = emailMap.hasKey("id") ? emailMap.getString("id") : null;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
ReadableArray postalAddresses = contact.hasKey("postalAddresses") ? contact.getArray("postalAddresses") : null;
|
|
909
|
+
int numOfPostalAddresses = 0;
|
|
910
|
+
String[] postalAddressesStreet = null;
|
|
911
|
+
String[] postalAddressesCity = null;
|
|
912
|
+
String[] postalAddressesState = null;
|
|
913
|
+
String[] postalAddressesRegion = null;
|
|
914
|
+
String[] postalAddressesPostCode = null;
|
|
915
|
+
String[] postalAddressesCountry = null;
|
|
916
|
+
Integer[] postalAddressesType = null;
|
|
917
|
+
String[] postalAddressesLabel = null;
|
|
918
|
+
if (postalAddresses != null) {
|
|
919
|
+
numOfPostalAddresses = postalAddresses.size();
|
|
920
|
+
postalAddressesStreet = new String[numOfPostalAddresses];
|
|
921
|
+
postalAddressesCity = new String[numOfPostalAddresses];
|
|
922
|
+
postalAddressesState = new String[numOfPostalAddresses];
|
|
923
|
+
postalAddressesRegion = new String[numOfPostalAddresses];
|
|
924
|
+
postalAddressesPostCode = new String[numOfPostalAddresses];
|
|
925
|
+
postalAddressesCountry = new String[numOfPostalAddresses];
|
|
926
|
+
postalAddressesType = new Integer[numOfPostalAddresses];
|
|
927
|
+
postalAddressesLabel = new String[numOfPostalAddresses];
|
|
928
|
+
for (int i = 0; i < numOfPostalAddresses; i++) {
|
|
929
|
+
String postalLabel = getValueFromKey(postalAddresses.getMap(i), "label");
|
|
930
|
+
postalAddressesStreet[i] = getValueFromKey(postalAddresses.getMap(i), "street");
|
|
931
|
+
postalAddressesCity[i] = getValueFromKey(postalAddresses.getMap(i), "city");
|
|
932
|
+
postalAddressesState[i] = getValueFromKey(postalAddresses.getMap(i), "state");
|
|
933
|
+
postalAddressesRegion[i] = getValueFromKey(postalAddresses.getMap(i), "region");
|
|
934
|
+
postalAddressesPostCode[i] = getValueFromKey(postalAddresses.getMap(i), "postCode");
|
|
935
|
+
postalAddressesCountry[i] = getValueFromKey(postalAddresses.getMap(i), "country");
|
|
936
|
+
postalAddressesType[i] = mapStringToPostalAddressType(postalLabel);
|
|
937
|
+
postalAddressesLabel[i] = postalLabel;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
ReadableArray imAddresses = contact.hasKey("imAddresses") ? contact.getArray("imAddresses") : null;
|
|
942
|
+
int numOfIMAddresses = 0;
|
|
943
|
+
String[] imAccounts = null;
|
|
944
|
+
String[] imProtocols = null;
|
|
945
|
+
String[] imAddressIds = null;
|
|
946
|
+
|
|
947
|
+
if (imAddresses != null) {
|
|
948
|
+
numOfIMAddresses = imAddresses.size();
|
|
949
|
+
imAccounts = new String[numOfIMAddresses];
|
|
950
|
+
imProtocols = new String[numOfIMAddresses];
|
|
951
|
+
imAddressIds = new String[numOfIMAddresses];
|
|
952
|
+
for (int i = 0; i < numOfIMAddresses; i++) {
|
|
953
|
+
ReadableMap imAddressMap = imAddresses.getMap(i);
|
|
954
|
+
imAccounts[i] = imAddressMap.getString("username");
|
|
955
|
+
imProtocols[i] = imAddressMap.getString("service");
|
|
956
|
+
imAddressIds[i] = imAddressMap.hasKey("id") ? imAddressMap.getString("id") : null;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
|
|
961
|
+
|
|
962
|
+
ContentProviderOperation.Builder op = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
|
|
963
|
+
.withSelection(ContactsContract.Data.CONTACT_ID + "=?", new String[] { String.valueOf(recordID) })
|
|
964
|
+
.withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
|
|
965
|
+
.withValue(StructuredName.GIVEN_NAME, givenName)
|
|
966
|
+
.withValue(StructuredName.MIDDLE_NAME, middleName)
|
|
967
|
+
.withValue(StructuredName.FAMILY_NAME, familyName)
|
|
968
|
+
.withValue(StructuredName.PREFIX, prefix)
|
|
969
|
+
.withValue(StructuredName.SUFFIX, suffix);
|
|
970
|
+
ops.add(op.build());
|
|
971
|
+
|
|
972
|
+
op = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
|
|
973
|
+
.withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + " = ?",
|
|
974
|
+
new String[] { String.valueOf(recordID), Organization.CONTENT_ITEM_TYPE })
|
|
975
|
+
.withValue(Organization.COMPANY, company)
|
|
976
|
+
.withValue(Organization.TITLE, jobTitle)
|
|
977
|
+
.withValue(Organization.DEPARTMENT, department);
|
|
978
|
+
ops.add(op.build());
|
|
979
|
+
|
|
980
|
+
op.withYieldAllowed(true);
|
|
981
|
+
|
|
982
|
+
if (phoneNumbers != null) {
|
|
983
|
+
// remove existing phoneNumbers first
|
|
984
|
+
op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
985
|
+
.withSelection(
|
|
986
|
+
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
|
|
987
|
+
new String[] { String.valueOf(CommonDataKinds.Phone.CONTENT_ITEM_TYPE),
|
|
988
|
+
String.valueOf(rawContactId) });
|
|
989
|
+
ops.add(op.build());
|
|
990
|
+
|
|
991
|
+
// add passed phonenumbers
|
|
992
|
+
for (int i = 0; i < numOfPhones; i++) {
|
|
993
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
994
|
+
.withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
|
|
995
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
|
996
|
+
.withValue(CommonDataKinds.Phone.NUMBER, phones[i])
|
|
997
|
+
.withValue(CommonDataKinds.Phone.TYPE, phonesTypes[i])
|
|
998
|
+
.withValue(CommonDataKinds.Phone.LABEL, phonesLabels[i]);
|
|
999
|
+
ops.add(op.build());
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
for (int i = 0; i < numOfUrls; i++) {
|
|
1004
|
+
if (urlIds[i] == null) {
|
|
1005
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
1006
|
+
.withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
|
|
1007
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Website.CONTENT_ITEM_TYPE)
|
|
1008
|
+
.withValue(CommonDataKinds.Website.URL, urls[i]);
|
|
1009
|
+
} else {
|
|
1010
|
+
op = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
|
|
1011
|
+
.withSelection(ContactsContract.Data._ID + "=?", new String[] { String.valueOf(urlIds[i]) })
|
|
1012
|
+
.withValue(CommonDataKinds.Website.URL, urls[i]);
|
|
1013
|
+
}
|
|
1014
|
+
ops.add(op.build());
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (emailAddresses != null) {
|
|
1018
|
+
// remove existing emails first
|
|
1019
|
+
op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
1020
|
+
.withSelection(
|
|
1021
|
+
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
|
|
1022
|
+
new String[] { String.valueOf(CommonDataKinds.Email.CONTENT_ITEM_TYPE),
|
|
1023
|
+
String.valueOf(rawContactId) });
|
|
1024
|
+
ops.add(op.build());
|
|
1025
|
+
|
|
1026
|
+
// add passed email addresses
|
|
1027
|
+
for (int i = 0; i < numOfEmails; i++) {
|
|
1028
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
1029
|
+
.withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
|
|
1030
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|
|
1031
|
+
.withValue(CommonDataKinds.Email.ADDRESS, emails[i])
|
|
1032
|
+
.withValue(CommonDataKinds.Email.TYPE, emailsTypes[i])
|
|
1033
|
+
.withValue(CommonDataKinds.Email.LABEL, emailsLabels[i]);
|
|
1034
|
+
ops.add(op.build());
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// remove existing note first
|
|
1039
|
+
op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
1040
|
+
.withSelection(
|
|
1041
|
+
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
|
|
1042
|
+
new String[] { String.valueOf(Note.CONTENT_ITEM_TYPE), String.valueOf(rawContactId) });
|
|
1043
|
+
ops.add(op.build());
|
|
1044
|
+
|
|
1045
|
+
if (note != null) {
|
|
1046
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
1047
|
+
.withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
|
|
1048
|
+
.withValue(ContactsContract.Data.MIMETYPE, Note.CONTENT_ITEM_TYPE)
|
|
1049
|
+
.withValue(Note.NOTE, note);
|
|
1050
|
+
ops.add(op.build());
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
if (thumbnailPath != null && !thumbnailPath.isEmpty()) {
|
|
1054
|
+
Bitmap photo = getThumbnailBitmap(thumbnailPath);
|
|
1055
|
+
|
|
1056
|
+
if (photo != null) {
|
|
1057
|
+
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
1058
|
+
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
|
1059
|
+
.withValue(ContactsContract.Data.MIMETYPE,
|
|
1060
|
+
CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
|
|
1061
|
+
.withValue(CommonDataKinds.Photo.PHOTO, toByteArray(photo))
|
|
1062
|
+
.build());
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
if (postalAddresses != null) {
|
|
1067
|
+
// remove existing addresses
|
|
1068
|
+
op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
1069
|
+
.withSelection(
|
|
1070
|
+
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
|
|
1071
|
+
new String[] { String.valueOf(CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE),
|
|
1072
|
+
String.valueOf(rawContactId) });
|
|
1073
|
+
ops.add(op.build());
|
|
1074
|
+
|
|
1075
|
+
for (int i = 0; i < numOfPostalAddresses; i++) {
|
|
1076
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
1077
|
+
.withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
|
|
1078
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
|
|
1079
|
+
.withValue(CommonDataKinds.StructuredPostal.TYPE, postalAddressesType[i])
|
|
1080
|
+
.withValue(CommonDataKinds.StructuredPostal.LABEL, postalAddressesLabel[i])
|
|
1081
|
+
.withValue(CommonDataKinds.StructuredPostal.STREET, postalAddressesStreet[i])
|
|
1082
|
+
.withValue(CommonDataKinds.StructuredPostal.CITY, postalAddressesCity[i])
|
|
1083
|
+
.withValue(CommonDataKinds.StructuredPostal.REGION, postalAddressesState[i])
|
|
1084
|
+
.withValue(CommonDataKinds.StructuredPostal.POSTCODE, postalAddressesPostCode[i])
|
|
1085
|
+
.withValue(CommonDataKinds.StructuredPostal.COUNTRY, postalAddressesCountry[i]);
|
|
1086
|
+
ops.add(op.build());
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
if (imAddresses != null) {
|
|
1091
|
+
// remove existing IM addresses
|
|
1092
|
+
op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
|
|
1093
|
+
.withSelection(
|
|
1094
|
+
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
|
|
1095
|
+
new String[] { String.valueOf(CommonDataKinds.Im.CONTENT_ITEM_TYPE),
|
|
1096
|
+
String.valueOf(rawContactId) });
|
|
1097
|
+
ops.add(op.build());
|
|
1098
|
+
|
|
1099
|
+
// add passed IM addresses
|
|
1100
|
+
for (int i = 0; i < numOfIMAddresses; i++) {
|
|
1101
|
+
op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
|
1102
|
+
.withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
|
|
1103
|
+
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Im.CONTENT_ITEM_TYPE)
|
|
1104
|
+
.withValue(CommonDataKinds.Im.DATA, imAccounts[i])
|
|
1105
|
+
.withValue(CommonDataKinds.Im.TYPE, CommonDataKinds.Im.TYPE_HOME)
|
|
1106
|
+
.withValue(CommonDataKinds.Im.PROTOCOL, CommonDataKinds.Im.PROTOCOL_CUSTOM)
|
|
1107
|
+
.withValue(CommonDataKinds.Im.CUSTOM_PROTOCOL, imProtocols[i]);
|
|
1108
|
+
ops.add(op.build());
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
Context ctx = getReactApplicationContext();
|
|
1113
|
+
try {
|
|
1114
|
+
ContentResolver cr = ctx.getContentResolver();
|
|
1115
|
+
ContentProviderResult[] result = cr.applyBatch(ContactsContract.AUTHORITY, ops);
|
|
1116
|
+
|
|
1117
|
+
if (result != null && result.length > 0) {
|
|
1118
|
+
|
|
1119
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
1120
|
+
WritableMap updatedContact = contactsProvider.getContactById(recordID);
|
|
1121
|
+
|
|
1122
|
+
promise.resolve(updatedContact); // success
|
|
1123
|
+
}
|
|
1124
|
+
} catch (Exception e) {
|
|
1125
|
+
promise.reject(e.toString());
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/*
|
|
1130
|
+
* Update contact to phone's addressbook
|
|
1131
|
+
*/
|
|
1132
|
+
@Override
|
|
1133
|
+
public void deleteContact(ReadableMap contact, Promise promise) {
|
|
1134
|
+
|
|
1135
|
+
String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
|
|
1136
|
+
|
|
1137
|
+
try {
|
|
1138
|
+
Context ctx = getReactApplicationContext();
|
|
1139
|
+
|
|
1140
|
+
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, recordID);
|
|
1141
|
+
ContentResolver cr = ctx.getContentResolver();
|
|
1142
|
+
int deleted = cr.delete(uri, null, null);
|
|
1143
|
+
|
|
1144
|
+
if (deleted > 0)
|
|
1145
|
+
promise.resolve(recordID); // success
|
|
1146
|
+
else
|
|
1147
|
+
promise.resolve(null); // something was wrong
|
|
1148
|
+
|
|
1149
|
+
} catch (Exception e) {
|
|
1150
|
+
promise.reject(e.toString());
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
/*
|
|
1155
|
+
* Check permission
|
|
1156
|
+
*/
|
|
1157
|
+
@Override
|
|
1158
|
+
public void checkPermission(Promise promise) {
|
|
1159
|
+
promise.resolve(isPermissionGranted());
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/*
|
|
1163
|
+
* Request permission
|
|
1164
|
+
*/
|
|
1165
|
+
@Override
|
|
1166
|
+
public void requestPermission(Promise promise) {
|
|
1167
|
+
requestReadContactsPermission(promise);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/*
|
|
1171
|
+
* Enable note usage
|
|
1172
|
+
*/
|
|
1173
|
+
@Override
|
|
1174
|
+
public void iosEnableNotesUsage(boolean enabled) {
|
|
1175
|
+
// this method is only needed for iOS
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
private void requestReadContactsPermission(Promise promise) {
|
|
1179
|
+
Activity currentActivity = getCurrentActivity();
|
|
1180
|
+
if (currentActivity == null) {
|
|
1181
|
+
promise.reject(PERMISSION_DENIED);
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (isPermissionGranted().equals(PERMISSION_AUTHORIZED)) {
|
|
1186
|
+
promise.resolve(PERMISSION_AUTHORIZED);
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
requestPromise = promise;
|
|
1191
|
+
ActivityCompat.requestPermissions(currentActivity, new String[] { PERMISSION_READ_CONTACTS },
|
|
1192
|
+
PERMISSION_REQUEST_CODE);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
protected static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
|
1196
|
+
@NonNull int[] grantResults) {
|
|
1197
|
+
if (requestPromise == null) {
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
if (requestCode != PERMISSION_REQUEST_CODE) {
|
|
1202
|
+
requestPromise.resolve(PERMISSION_DENIED);
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
Hashtable<String, Boolean> results = new Hashtable<>();
|
|
1207
|
+
for (int i = 0; i < permissions.length; i++) {
|
|
1208
|
+
results.put(permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
if (results.containsKey(PERMISSION_READ_CONTACTS) && results.get(PERMISSION_READ_CONTACTS)) {
|
|
1212
|
+
requestPromise.resolve(PERMISSION_AUTHORIZED);
|
|
1213
|
+
} else {
|
|
1214
|
+
requestPromise.resolve(PERMISSION_DENIED);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
requestPromise = null;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/*
|
|
1221
|
+
* Get string value from key
|
|
1222
|
+
*/
|
|
1223
|
+
private String getValueFromKey(ReadableMap item, String key) {
|
|
1224
|
+
return item.hasKey(key) ? item.getString(key) : "";
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/*
|
|
1228
|
+
* Check if READ_CONTACTS permission is granted
|
|
1229
|
+
*/
|
|
1230
|
+
private String isPermissionGranted() {
|
|
1231
|
+
// return -1 for denied and 1
|
|
1232
|
+
int res = getReactApplicationContext().checkSelfPermission(PERMISSION_READ_CONTACTS);
|
|
1233
|
+
return (res == PackageManager.PERMISSION_GRANTED) ? PERMISSION_AUTHORIZED : PERMISSION_DENIED;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/*
|
|
1237
|
+
* TODO support all phone types
|
|
1238
|
+
* http://developer.android.com/reference/android/provider/ContactsContract.
|
|
1239
|
+
* CommonDataKinds.Phone.html
|
|
1240
|
+
*/
|
|
1241
|
+
private int mapStringToPhoneType(String label) {
|
|
1242
|
+
int phoneType;
|
|
1243
|
+
switch (label) {
|
|
1244
|
+
case "home":
|
|
1245
|
+
phoneType = CommonDataKinds.Phone.TYPE_HOME;
|
|
1246
|
+
break;
|
|
1247
|
+
case "work":
|
|
1248
|
+
phoneType = CommonDataKinds.Phone.TYPE_WORK;
|
|
1249
|
+
break;
|
|
1250
|
+
case "mobile":
|
|
1251
|
+
phoneType = CommonDataKinds.Phone.TYPE_MOBILE;
|
|
1252
|
+
break;
|
|
1253
|
+
case "main":
|
|
1254
|
+
phoneType = CommonDataKinds.Phone.TYPE_MAIN;
|
|
1255
|
+
break;
|
|
1256
|
+
case "work fax":
|
|
1257
|
+
phoneType = CommonDataKinds.Phone.TYPE_FAX_WORK;
|
|
1258
|
+
break;
|
|
1259
|
+
case "home fax":
|
|
1260
|
+
phoneType = CommonDataKinds.Phone.TYPE_FAX_HOME;
|
|
1261
|
+
break;
|
|
1262
|
+
case "pager":
|
|
1263
|
+
phoneType = CommonDataKinds.Phone.TYPE_PAGER;
|
|
1264
|
+
break;
|
|
1265
|
+
case "work_pager":
|
|
1266
|
+
phoneType = CommonDataKinds.Phone.TYPE_WORK_PAGER;
|
|
1267
|
+
break;
|
|
1268
|
+
case "work_mobile":
|
|
1269
|
+
phoneType = CommonDataKinds.Phone.TYPE_WORK_MOBILE;
|
|
1270
|
+
break;
|
|
1271
|
+
case "other":
|
|
1272
|
+
phoneType = CommonDataKinds.Phone.TYPE_OTHER;
|
|
1273
|
+
break;
|
|
1274
|
+
case "cell":
|
|
1275
|
+
phoneType = CommonDataKinds.Phone.TYPE_MOBILE;
|
|
1276
|
+
break;
|
|
1277
|
+
default:
|
|
1278
|
+
phoneType = CommonDataKinds.Phone.TYPE_CUSTOM;
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
return phoneType;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/*
|
|
1285
|
+
* TODO support TYPE_CUSTOM
|
|
1286
|
+
* http://developer.android.com/reference/android/provider/ContactsContract.
|
|
1287
|
+
* CommonDataKinds.Email.html
|
|
1288
|
+
*/
|
|
1289
|
+
private int mapStringToEmailType(String label) {
|
|
1290
|
+
int emailType;
|
|
1291
|
+
switch (label) {
|
|
1292
|
+
case "home":
|
|
1293
|
+
emailType = CommonDataKinds.Email.TYPE_HOME;
|
|
1294
|
+
break;
|
|
1295
|
+
case "work":
|
|
1296
|
+
emailType = CommonDataKinds.Email.TYPE_WORK;
|
|
1297
|
+
break;
|
|
1298
|
+
case "mobile":
|
|
1299
|
+
emailType = CommonDataKinds.Email.TYPE_MOBILE;
|
|
1300
|
+
break;
|
|
1301
|
+
case "other":
|
|
1302
|
+
emailType = CommonDataKinds.Email.TYPE_OTHER;
|
|
1303
|
+
break;
|
|
1304
|
+
case "personal":
|
|
1305
|
+
emailType = CommonDataKinds.Email.TYPE_HOME;
|
|
1306
|
+
break;
|
|
1307
|
+
default:
|
|
1308
|
+
emailType = CommonDataKinds.Email.TYPE_CUSTOM;
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
return emailType;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
private int mapStringToPostalAddressType(String label) {
|
|
1315
|
+
int postalAddressType;
|
|
1316
|
+
switch (label) {
|
|
1317
|
+
case "home":
|
|
1318
|
+
postalAddressType = CommonDataKinds.StructuredPostal.TYPE_HOME;
|
|
1319
|
+
break;
|
|
1320
|
+
case "work":
|
|
1321
|
+
postalAddressType = CommonDataKinds.StructuredPostal.TYPE_WORK;
|
|
1322
|
+
break;
|
|
1323
|
+
default:
|
|
1324
|
+
postalAddressType = CommonDataKinds.StructuredPostal.TYPE_CUSTOM;
|
|
1325
|
+
break;
|
|
1326
|
+
}
|
|
1327
|
+
return postalAddressType;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
@Override
|
|
1331
|
+
public String getName() {
|
|
1332
|
+
return ContactsProvider.NAME;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/*
|
|
1336
|
+
* Required for ActivityEventListener
|
|
1337
|
+
*/
|
|
1338
|
+
@Override
|
|
1339
|
+
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
|
|
1340
|
+
if (requestCode != REQUEST_OPEN_CONTACT_FORM && requestCode != REQUEST_OPEN_EXISTING_CONTACT) {
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
if (updateContactPromise == null) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
if (resultCode != Activity.RESULT_OK) {
|
|
1349
|
+
updateContactPromise.resolve(null); // user probably pressed cancel
|
|
1350
|
+
updateContactPromise = null;
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
if (data == null) {
|
|
1355
|
+
updateContactPromise.reject("Error received activity result with no data!");
|
|
1356
|
+
updateContactPromise = null;
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
try {
|
|
1361
|
+
Uri contactUri = data.getData();
|
|
1362
|
+
|
|
1363
|
+
if (contactUri == null) {
|
|
1364
|
+
updateContactPromise.reject("Error wrong data. No content uri found!"); // something was wrong
|
|
1365
|
+
updateContactPromise = null;
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
Context ctx = getReactApplicationContext();
|
|
1370
|
+
ContentResolver cr = ctx.getContentResolver();
|
|
1371
|
+
ContactsProvider contactsProvider = new ContactsProvider(cr);
|
|
1372
|
+
WritableMap newlyModifiedContact = contactsProvider.getContactById(contactUri.getLastPathSegment());
|
|
1373
|
+
|
|
1374
|
+
updateContactPromise.resolve(newlyModifiedContact); // success
|
|
1375
|
+
} catch (Exception e) {
|
|
1376
|
+
updateContactPromise.reject(e.getMessage());
|
|
1377
|
+
}
|
|
1378
|
+
updateContactPromise = null;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
/*
|
|
1382
|
+
* Required for ActivityEventListener
|
|
1383
|
+
*/
|
|
1384
|
+
@Override
|
|
1385
|
+
public void onNewIntent(Intent intent) {
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
}
|