@capgo/capacitor-contacts 8.0.4 → 8.0.5
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.
|
@@ -39,7 +39,8 @@ import java.util.Set;
|
|
|
39
39
|
)
|
|
40
40
|
public class CapacitorContactsPlugin extends Plugin {
|
|
41
41
|
|
|
42
|
-
private final String pluginVersion = "8.0.
|
|
42
|
+
private final String pluginVersion = "8.0.5";
|
|
43
|
+
private static final int BATCH_SIZE = 50;
|
|
43
44
|
|
|
44
45
|
// MARK: - Implemented API surface
|
|
45
46
|
|
|
@@ -76,15 +77,15 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
Integer
|
|
81
|
-
|
|
80
|
+
Integer limit = call.getInt("limit", null);
|
|
81
|
+
Integer offset = call.getInt("offset", null);
|
|
82
|
+
Set<String> fields = parseFieldsArray(call);
|
|
82
83
|
|
|
83
84
|
try {
|
|
84
|
-
List<ContactBuilder> builders = fetchContacts(limit, offset);
|
|
85
|
+
List<ContactBuilder> builders = fetchContacts(limit, offset, fields);
|
|
85
86
|
JSArray contacts = new JSArray();
|
|
86
87
|
for (ContactBuilder builder : builders) {
|
|
87
|
-
contacts.put(builder.toJSObject());
|
|
88
|
+
contacts.put(builder.toJSObject(fields));
|
|
88
89
|
}
|
|
89
90
|
JSObject result = new JSObject();
|
|
90
91
|
result.put("contacts", contacts);
|
|
@@ -101,21 +102,22 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
String identifier = options.getString("id");
|
|
105
|
+
String identifier = call.getString("id");
|
|
106
106
|
if (identifier == null) {
|
|
107
107
|
call.reject("Missing contact identifier.");
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
try {
|
|
112
|
-
|
|
112
|
+
Set<String> fields = parseFieldsArray(call);
|
|
113
|
+
ContactBuilder builder = fetchContact(identifier, fields);
|
|
113
114
|
if (builder == null) {
|
|
114
115
|
call.resolve(new JSObject().put("contact", null));
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
118
|
+
|
|
117
119
|
JSObject result = new JSObject();
|
|
118
|
-
result.put("contact", builder.toJSObject());
|
|
120
|
+
result.put("contact", builder.toJSObject(fields));
|
|
119
121
|
call.resolve(result);
|
|
120
122
|
} catch (Exception ex) {
|
|
121
123
|
call.reject("Failed to fetch contact.", null, ex);
|
|
@@ -215,8 +217,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
215
217
|
return;
|
|
216
218
|
}
|
|
217
219
|
|
|
218
|
-
JSObject
|
|
219
|
-
JSObject contactData = options.getJSObject("contact");
|
|
220
|
+
JSObject contactData = call.getObject("contact");
|
|
220
221
|
if (contactData == null) {
|
|
221
222
|
call.reject("Missing contact data.");
|
|
222
223
|
return;
|
|
@@ -237,9 +238,8 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
237
238
|
return;
|
|
238
239
|
}
|
|
239
240
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
JSObject contactData = options.getJSObject("contact");
|
|
241
|
+
String contactId = call.getString("id");
|
|
242
|
+
JSObject contactData = call.getObject("contact");
|
|
243
243
|
|
|
244
244
|
if (contactId == null || contactData == null) {
|
|
245
245
|
call.reject("Missing contact identifier or data.");
|
|
@@ -261,8 +261,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
261
261
|
return;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
String contactId = options.getString("id");
|
|
264
|
+
String contactId = call.getString("id");
|
|
266
265
|
|
|
267
266
|
if (contactId == null) {
|
|
268
267
|
call.reject("Missing contact identifier.");
|
|
@@ -327,8 +326,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
327
326
|
return;
|
|
328
327
|
}
|
|
329
328
|
|
|
330
|
-
|
|
331
|
-
String groupId = options.getString("id");
|
|
329
|
+
String groupId = call.getString("id");
|
|
332
330
|
|
|
333
331
|
if (groupId == null) {
|
|
334
332
|
call.reject("Missing group identifier.");
|
|
@@ -368,8 +366,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
368
366
|
return;
|
|
369
367
|
}
|
|
370
368
|
|
|
371
|
-
JSObject
|
|
372
|
-
JSObject groupData = options.getJSObject("group");
|
|
369
|
+
JSObject groupData = call.getObject("group");
|
|
373
370
|
|
|
374
371
|
if (groupData == null) {
|
|
375
372
|
call.reject("Missing group data.");
|
|
@@ -411,8 +408,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
411
408
|
return;
|
|
412
409
|
}
|
|
413
410
|
|
|
414
|
-
|
|
415
|
-
String groupId = options.getString("id");
|
|
411
|
+
String groupId = call.getString("id");
|
|
416
412
|
|
|
417
413
|
if (groupId == null) {
|
|
418
414
|
call.reject("Missing group identifier.");
|
|
@@ -462,8 +458,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
462
458
|
|
|
463
459
|
@PluginMethod
|
|
464
460
|
public void displayContactById(PluginCall call) {
|
|
465
|
-
|
|
466
|
-
String contactId = options.getString("id");
|
|
461
|
+
String contactId = call.getString("id");
|
|
467
462
|
|
|
468
463
|
if (contactId == null) {
|
|
469
464
|
call.reject("Missing contact identifier.");
|
|
@@ -485,12 +480,9 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
485
480
|
currentPickerCall = call;
|
|
486
481
|
Intent intent = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
|
|
487
482
|
|
|
488
|
-
JSObject
|
|
489
|
-
if (
|
|
490
|
-
|
|
491
|
-
if (contactData != null) {
|
|
492
|
-
populateIntent(intent, contactData);
|
|
493
|
-
}
|
|
483
|
+
JSObject contactData = call.getObject("contact");
|
|
484
|
+
if (contactData != null) {
|
|
485
|
+
populateIntent(intent, contactData);
|
|
494
486
|
}
|
|
495
487
|
|
|
496
488
|
startActivityForResult(call, intent, CREATE_CONTACT_REQUEST);
|
|
@@ -498,8 +490,7 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
498
490
|
|
|
499
491
|
@PluginMethod
|
|
500
492
|
public void displayUpdateContactById(PluginCall call) {
|
|
501
|
-
|
|
502
|
-
String contactId = options.getString("id");
|
|
493
|
+
String contactId = call.getString("id");
|
|
503
494
|
|
|
504
495
|
if (contactId == null) {
|
|
505
496
|
call.reject("Missing contact identifier.");
|
|
@@ -542,10 +533,10 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
542
533
|
if (data != null && data.getData() != null) {
|
|
543
534
|
String contactId = getContactIdFromUri(data.getData());
|
|
544
535
|
if (contactId != null) {
|
|
545
|
-
ContactBuilder builder = fetchContact(contactId);
|
|
536
|
+
ContactBuilder builder = fetchContact(contactId, null);
|
|
546
537
|
if (builder != null) {
|
|
547
538
|
JSArray contacts = new JSArray();
|
|
548
|
-
contacts.put(builder.toJSObject());
|
|
539
|
+
contacts.put(builder.toJSObject(null));
|
|
549
540
|
call.resolve(new JSObject().put("contacts", contacts));
|
|
550
541
|
} else {
|
|
551
542
|
call.resolve(new JSObject().put("contacts", new JSArray()));
|
|
@@ -1061,8 +1052,8 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1061
1052
|
|
|
1062
1053
|
// MARK: - Contact access helpers
|
|
1063
1054
|
|
|
1064
|
-
private List<ContactBuilder> fetchContacts(Integer limit, Integer offset) {
|
|
1065
|
-
|
|
1055
|
+
private List<ContactBuilder> fetchContacts(Integer limit, Integer offset, Set<String> fields) {
|
|
1056
|
+
Map<String, ContactBuilder> builderMap = new java.util.LinkedHashMap<>();
|
|
1066
1057
|
ContentResolver resolver = getContext().getContentResolver();
|
|
1067
1058
|
|
|
1068
1059
|
Uri queryUri = ContactsContract.Contacts.CONTENT_URI;
|
|
@@ -1086,163 +1077,189 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1086
1077
|
)
|
|
1087
1078
|
) {
|
|
1088
1079
|
if (cursor == null) {
|
|
1089
|
-
return
|
|
1080
|
+
return new ArrayList<>();
|
|
1090
1081
|
}
|
|
1091
1082
|
|
|
1092
1083
|
while (cursor.moveToNext()) {
|
|
1093
1084
|
String id = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1085
|
+
String displayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY));
|
|
1086
|
+
ContactBuilder builder = new ContactBuilder(id);
|
|
1087
|
+
builder.fullName = displayName;
|
|
1088
|
+
builderMap.put(id, builder);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (!builderMap.isEmpty()) {
|
|
1093
|
+
List<String> allIds = new ArrayList<>(builderMap.keySet());
|
|
1094
|
+
|
|
1095
|
+
for (int i = 0; i < allIds.size(); i += BATCH_SIZE) {
|
|
1096
|
+
List<String> batchIds = allIds.subList(i, Math.min(i + BATCH_SIZE, allIds.size()));
|
|
1097
|
+
fillContactData(builderMap, batchIds, fields);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
if (fields == null || fields.contains("account")) {
|
|
1101
|
+
for (int i = 0; i < allIds.size(); i += BATCH_SIZE) {
|
|
1102
|
+
List<String> batchIds = allIds.subList(i, Math.min(i + BATCH_SIZE, allIds.size()));
|
|
1103
|
+
fillAccountInfo(builderMap, batchIds);
|
|
1098
1104
|
}
|
|
1099
1105
|
}
|
|
1100
1106
|
}
|
|
1101
1107
|
|
|
1102
|
-
return
|
|
1108
|
+
return new ArrayList<>(builderMap.values());
|
|
1103
1109
|
}
|
|
1104
1110
|
|
|
1105
|
-
private
|
|
1111
|
+
private void fillContactData(Map<String, ContactBuilder> builderMap, List<String> batchIds, Set<String> fields) {
|
|
1106
1112
|
ContentResolver resolver = getContext().getContentResolver();
|
|
1107
|
-
|
|
1113
|
+
List<String> selectionArgs = new ArrayList<>(batchIds);
|
|
1114
|
+
StringBuilder selection = new StringBuilder();
|
|
1115
|
+
|
|
1116
|
+
selection.append(ContactsContract.Data.CONTACT_ID + " IN (");
|
|
1117
|
+
for (int i = 0; i < batchIds.size(); i++) {
|
|
1118
|
+
if (i > 0) selection.append(",");
|
|
1119
|
+
selection.append("?");
|
|
1120
|
+
}
|
|
1121
|
+
selection.append(")");
|
|
1122
|
+
|
|
1123
|
+
if (fields != null) {
|
|
1124
|
+
List<String> mimeTypes = getMimeTypesForFields(fields);
|
|
1125
|
+
|
|
1126
|
+
if (!mimeTypes.isEmpty()) {
|
|
1127
|
+
StringBuilder mimeSelection = new StringBuilder();
|
|
1128
|
+
mimeSelection.append(" AND " + ContactsContract.Data.MIMETYPE + " IN (");
|
|
1129
|
+
for (int i = 0; i < mimeTypes.size(); i++) {
|
|
1130
|
+
if (i > 0) mimeSelection.append(",");
|
|
1131
|
+
mimeSelection.append("?");
|
|
1132
|
+
selectionArgs.add(mimeTypes.get(i));
|
|
1133
|
+
}
|
|
1134
|
+
mimeSelection.append(")");
|
|
1135
|
+
selection.append(mimeSelection.toString());
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1108
1138
|
|
|
1109
|
-
// Structured name, emails, phones, etc.
|
|
1110
1139
|
try (
|
|
1111
1140
|
Cursor dataCursor = resolver.query(
|
|
1112
1141
|
ContactsContract.Data.CONTENT_URI,
|
|
1113
1142
|
null,
|
|
1114
|
-
|
|
1115
|
-
new String[]
|
|
1143
|
+
selection.toString(),
|
|
1144
|
+
selectionArgs.toArray(new String[0]),
|
|
1116
1145
|
null
|
|
1117
1146
|
)
|
|
1118
1147
|
) {
|
|
1119
|
-
if (dataCursor
|
|
1120
|
-
|
|
1148
|
+
if (dataCursor != null) {
|
|
1149
|
+
while (dataCursor.moveToNext()) {
|
|
1150
|
+
String contactId = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.Data.CONTACT_ID));
|
|
1151
|
+
ContactBuilder builder = builderMap.get(contactId);
|
|
1152
|
+
if (builder != null) {
|
|
1153
|
+
processDataRow(builder, dataCursor);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1121
1156
|
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1122
1159
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.LABEL)),
|
|
1156
|
-
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.IS_PRIMARY)) == 1
|
|
1157
|
-
);
|
|
1158
|
-
break;
|
|
1159
|
-
case ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE:
|
|
1160
|
-
builder.addPostalAddress(
|
|
1161
|
-
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)),
|
|
1162
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.LABEL)),
|
|
1163
|
-
dataCursor.getString(
|
|
1164
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.STREET)
|
|
1165
|
-
),
|
|
1166
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.CITY)),
|
|
1167
|
-
dataCursor.getString(
|
|
1168
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.REGION)
|
|
1169
|
-
),
|
|
1170
|
-
dataCursor.getString(
|
|
1171
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)
|
|
1172
|
-
),
|
|
1173
|
-
dataCursor.getString(
|
|
1174
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)
|
|
1175
|
-
),
|
|
1176
|
-
dataCursor.getString(
|
|
1177
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD)
|
|
1178
|
-
),
|
|
1179
|
-
dataCursor.getInt(
|
|
1180
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.IS_PRIMARY)
|
|
1181
|
-
) ==
|
|
1182
|
-
1
|
|
1183
|
-
);
|
|
1184
|
-
break;
|
|
1185
|
-
case ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE:
|
|
1186
|
-
builder.addUrlAddress(
|
|
1187
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.URL)),
|
|
1188
|
-
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.TYPE)),
|
|
1189
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.LABEL))
|
|
1190
|
-
);
|
|
1191
|
-
break;
|
|
1192
|
-
case ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE:
|
|
1193
|
-
builder.organizationName = dataCursor.getString(
|
|
1194
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.COMPANY)
|
|
1195
|
-
);
|
|
1196
|
-
builder.jobTitle = dataCursor.getString(
|
|
1197
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.TITLE)
|
|
1198
|
-
);
|
|
1199
|
-
break;
|
|
1200
|
-
case ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE:
|
|
1201
|
-
builder.note = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Note.NOTE));
|
|
1202
|
-
break;
|
|
1203
|
-
case ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE:
|
|
1204
|
-
int eventType = dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.TYPE));
|
|
1205
|
-
if (eventType == ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) {
|
|
1206
|
-
builder.setBirthday(
|
|
1207
|
-
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.START_DATE))
|
|
1208
|
-
);
|
|
1209
|
-
}
|
|
1210
|
-
break;
|
|
1211
|
-
case ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE:
|
|
1212
|
-
long groupId = dataCursor.getLong(
|
|
1213
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID)
|
|
1160
|
+
private void fillAccountInfo(Map<String, ContactBuilder> builderMap, List<String> batchIds) {
|
|
1161
|
+
ContentResolver resolver = getContext().getContentResolver();
|
|
1162
|
+
List<String> selectionArgs = new ArrayList<>(batchIds);
|
|
1163
|
+
StringBuilder selection = new StringBuilder();
|
|
1164
|
+
|
|
1165
|
+
selection.append(ContactsContract.RawContacts.CONTACT_ID + " IN (");
|
|
1166
|
+
for (int i = 0; i < batchIds.size(); i++) {
|
|
1167
|
+
if (i > 0) selection.append(",");
|
|
1168
|
+
selection.append("?");
|
|
1169
|
+
}
|
|
1170
|
+
selection.append(")");
|
|
1171
|
+
|
|
1172
|
+
try (
|
|
1173
|
+
Cursor rawCursor = resolver.query(
|
|
1174
|
+
ContactsContract.RawContacts.CONTENT_URI,
|
|
1175
|
+
new String[] {
|
|
1176
|
+
ContactsContract.RawContacts.CONTACT_ID,
|
|
1177
|
+
ContactsContract.RawContacts.ACCOUNT_NAME,
|
|
1178
|
+
ContactsContract.RawContacts.ACCOUNT_TYPE
|
|
1179
|
+
},
|
|
1180
|
+
selection.toString(),
|
|
1181
|
+
selectionArgs.toArray(new String[0]),
|
|
1182
|
+
null
|
|
1183
|
+
)
|
|
1184
|
+
) {
|
|
1185
|
+
if (rawCursor != null) {
|
|
1186
|
+
while (rawCursor.moveToNext()) {
|
|
1187
|
+
String contactId = rawCursor.getString(rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.CONTACT_ID));
|
|
1188
|
+
ContactBuilder builder = builderMap.get(contactId);
|
|
1189
|
+
if (builder != null && builder.accountName == null) {
|
|
1190
|
+
builder.accountName = rawCursor.getString(
|
|
1191
|
+
rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_NAME)
|
|
1214
1192
|
);
|
|
1215
|
-
builder.
|
|
1216
|
-
|
|
1217
|
-
case ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE:
|
|
1218
|
-
byte[] photoData = dataCursor.getBlob(
|
|
1219
|
-
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Photo.PHOTO)
|
|
1193
|
+
builder.accountType = rawCursor.getString(
|
|
1194
|
+
rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_TYPE)
|
|
1220
1195
|
);
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
private ContactBuilder fetchContact(@NonNull String contactId, Set<String> fields) {
|
|
1203
|
+
ContentResolver resolver = getContext().getContentResolver();
|
|
1204
|
+
ContactBuilder builder = new ContactBuilder(contactId);
|
|
1205
|
+
|
|
1206
|
+
// Build selection based on fields
|
|
1207
|
+
String selection = ContactsContract.Data.CONTACT_ID + " = ?";
|
|
1208
|
+
List<String> selectionArgs = new ArrayList<>();
|
|
1209
|
+
selectionArgs.add(contactId);
|
|
1210
|
+
|
|
1211
|
+
if (fields != null) {
|
|
1212
|
+
List<String> mimeTypes = getMimeTypesForFields(fields);
|
|
1213
|
+
|
|
1214
|
+
if (!mimeTypes.isEmpty()) {
|
|
1215
|
+
StringBuilder mimeSelection = new StringBuilder();
|
|
1216
|
+
mimeSelection.append(" AND " + ContactsContract.Data.MIMETYPE + " IN (");
|
|
1217
|
+
for (int i = 0; i < mimeTypes.size(); i++) {
|
|
1218
|
+
if (i > 0) mimeSelection.append(",");
|
|
1219
|
+
mimeSelection.append("?");
|
|
1220
|
+
selectionArgs.add(mimeTypes.get(i));
|
|
1227
1221
|
}
|
|
1222
|
+
mimeSelection.append(")");
|
|
1223
|
+
selection += mimeSelection.toString();
|
|
1228
1224
|
}
|
|
1229
1225
|
}
|
|
1230
1226
|
|
|
1231
|
-
//
|
|
1227
|
+
// Structured name, emails, phones, etc.
|
|
1232
1228
|
try (
|
|
1233
|
-
Cursor
|
|
1234
|
-
ContactsContract.
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
new String[]
|
|
1229
|
+
Cursor dataCursor = resolver.query(
|
|
1230
|
+
ContactsContract.Data.CONTENT_URI,
|
|
1231
|
+
null,
|
|
1232
|
+
selection,
|
|
1233
|
+
selectionArgs.toArray(new String[0]),
|
|
1238
1234
|
null
|
|
1239
1235
|
)
|
|
1240
1236
|
) {
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1237
|
+
if (dataCursor == null) {
|
|
1238
|
+
return null;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
while (dataCursor.moveToNext()) {
|
|
1242
|
+
processDataRow(builder, dataCursor);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Account information (only if fields allow)
|
|
1247
|
+
if (fields == null || fields.contains("account")) {
|
|
1248
|
+
try (
|
|
1249
|
+
Cursor rawCursor = resolver.query(
|
|
1250
|
+
ContactsContract.RawContacts.CONTENT_URI,
|
|
1251
|
+
new String[] { ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE },
|
|
1252
|
+
ContactsContract.RawContacts.CONTACT_ID + " = ?",
|
|
1253
|
+
new String[] { contactId },
|
|
1254
|
+
null
|
|
1255
|
+
)
|
|
1256
|
+
) {
|
|
1257
|
+
if (rawCursor != null && rawCursor.moveToFirst()) {
|
|
1258
|
+
String accountName = rawCursor.getString(rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_NAME));
|
|
1259
|
+
String accountType = rawCursor.getString(rawCursor.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_TYPE));
|
|
1260
|
+
builder.accountName = accountName;
|
|
1261
|
+
builder.accountType = accountType;
|
|
1262
|
+
}
|
|
1246
1263
|
}
|
|
1247
1264
|
}
|
|
1248
1265
|
|
|
@@ -1253,6 +1270,98 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1253
1270
|
return builder;
|
|
1254
1271
|
}
|
|
1255
1272
|
|
|
1273
|
+
private void processDataRow(ContactBuilder builder, Cursor dataCursor) {
|
|
1274
|
+
String mimeType = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE));
|
|
1275
|
+
switch (mimeType) {
|
|
1276
|
+
case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
|
|
1277
|
+
builder.givenName = dataCursor.getString(
|
|
1278
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
|
|
1279
|
+
);
|
|
1280
|
+
builder.familyName = dataCursor.getString(
|
|
1281
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)
|
|
1282
|
+
);
|
|
1283
|
+
builder.middleName = dataCursor.getString(
|
|
1284
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME)
|
|
1285
|
+
);
|
|
1286
|
+
builder.namePrefix = dataCursor.getString(
|
|
1287
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.PREFIX)
|
|
1288
|
+
);
|
|
1289
|
+
builder.nameSuffix = dataCursor.getString(
|
|
1290
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.SUFFIX)
|
|
1291
|
+
);
|
|
1292
|
+
break;
|
|
1293
|
+
case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE:
|
|
1294
|
+
builder.addEmail(
|
|
1295
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.ADDRESS)),
|
|
1296
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.TYPE)),
|
|
1297
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.LABEL)),
|
|
1298
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.IS_PRIMARY)) == 1
|
|
1299
|
+
);
|
|
1300
|
+
break;
|
|
1301
|
+
case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
|
|
1302
|
+
builder.addPhone(
|
|
1303
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)),
|
|
1304
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.TYPE)),
|
|
1305
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.LABEL)),
|
|
1306
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.IS_PRIMARY)) == 1
|
|
1307
|
+
);
|
|
1308
|
+
break;
|
|
1309
|
+
case ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE:
|
|
1310
|
+
builder.addPostalAddress(
|
|
1311
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.TYPE)),
|
|
1312
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.LABEL)),
|
|
1313
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.STREET)),
|
|
1314
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.CITY)),
|
|
1315
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.REGION)),
|
|
1316
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)),
|
|
1317
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)),
|
|
1318
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD)),
|
|
1319
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.IS_PRIMARY)) == 1
|
|
1320
|
+
);
|
|
1321
|
+
break;
|
|
1322
|
+
case ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE:
|
|
1323
|
+
builder.addUrlAddress(
|
|
1324
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.URL)),
|
|
1325
|
+
dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.TYPE)),
|
|
1326
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Website.LABEL))
|
|
1327
|
+
);
|
|
1328
|
+
break;
|
|
1329
|
+
case ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE:
|
|
1330
|
+
builder.organizationName = dataCursor.getString(
|
|
1331
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.COMPANY)
|
|
1332
|
+
);
|
|
1333
|
+
builder.jobTitle = dataCursor.getString(
|
|
1334
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Organization.TITLE)
|
|
1335
|
+
);
|
|
1336
|
+
break;
|
|
1337
|
+
case ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE:
|
|
1338
|
+
builder.note = dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Note.NOTE));
|
|
1339
|
+
break;
|
|
1340
|
+
case ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE:
|
|
1341
|
+
int eventType = dataCursor.getInt(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.TYPE));
|
|
1342
|
+
if (eventType == ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) {
|
|
1343
|
+
builder.setBirthday(
|
|
1344
|
+
dataCursor.getString(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Event.START_DATE))
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
break;
|
|
1348
|
+
case ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE:
|
|
1349
|
+
long groupId = dataCursor.getLong(
|
|
1350
|
+
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID)
|
|
1351
|
+
);
|
|
1352
|
+
builder.addGroupId(String.valueOf(groupId));
|
|
1353
|
+
break;
|
|
1354
|
+
case ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE:
|
|
1355
|
+
byte[] photoData = dataCursor.getBlob(dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Photo.PHOTO));
|
|
1356
|
+
if (photoData != null) {
|
|
1357
|
+
builder.photoBase64 = Base64.encodeToString(photoData, Base64.NO_WRAP);
|
|
1358
|
+
}
|
|
1359
|
+
break;
|
|
1360
|
+
default:
|
|
1361
|
+
break;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1256
1365
|
private String resolveDisplayName(String contactId) {
|
|
1257
1366
|
ContentResolver resolver = getContext().getContentResolver();
|
|
1258
1367
|
try (
|
|
@@ -1271,6 +1380,65 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1271
1380
|
return null;
|
|
1272
1381
|
}
|
|
1273
1382
|
|
|
1383
|
+
private Set<String> parseFieldsArray(PluginCall call) {
|
|
1384
|
+
JSArray fieldsArray = call.getArray("fields", null);
|
|
1385
|
+
if (fieldsArray == null) {
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
Set<String> fields = new HashSet<>();
|
|
1389
|
+
try {
|
|
1390
|
+
List<Object> list = fieldsArray.toList();
|
|
1391
|
+
for (Object item : list) {
|
|
1392
|
+
if (item instanceof String) {
|
|
1393
|
+
fields.add((String) item);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
} catch (Exception e) {
|
|
1397
|
+
// Return empty set if parsing fails
|
|
1398
|
+
}
|
|
1399
|
+
return fields.isEmpty() ? null : fields;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
private List<String> getMimeTypesForFields(Set<String> fields) {
|
|
1403
|
+
List<String> mimeTypes = new ArrayList<>();
|
|
1404
|
+
// Always fetch structured name for basic display
|
|
1405
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
|
|
1406
|
+
|
|
1407
|
+
if (fields == null) {
|
|
1408
|
+
return mimeTypes;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
if (fields.contains("organizationName") || fields.contains("jobTitle")) {
|
|
1412
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
|
|
1413
|
+
}
|
|
1414
|
+
if (fields.contains("emailAddresses")) {
|
|
1415
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
|
|
1416
|
+
}
|
|
1417
|
+
if (fields.contains("phoneNumbers")) {
|
|
1418
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
|
|
1419
|
+
}
|
|
1420
|
+
if (fields.contains("postalAddresses")) {
|
|
1421
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
|
|
1422
|
+
}
|
|
1423
|
+
if (fields.contains("urlAddresses")) {
|
|
1424
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
|
|
1425
|
+
}
|
|
1426
|
+
if (fields.contains("note")) {
|
|
1427
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
|
|
1428
|
+
}
|
|
1429
|
+
if (fields.contains("birthday")) {
|
|
1430
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
|
|
1431
|
+
}
|
|
1432
|
+
if (fields.contains("groupIds")) {
|
|
1433
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
|
|
1434
|
+
}
|
|
1435
|
+
if (fields.contains("photo")) {
|
|
1436
|
+
mimeTypes.add(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
return mimeTypes;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1274
1442
|
// MARK: - Contact builder helper
|
|
1275
1443
|
|
|
1276
1444
|
private static class ContactBuilder {
|
|
@@ -1381,36 +1549,50 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1381
1549
|
if (startDate == null || startDate.isEmpty()) {
|
|
1382
1550
|
return;
|
|
1383
1551
|
}
|
|
1384
|
-
|
|
1385
|
-
if (
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1552
|
+
// Handle yearless dates: --MM-DD
|
|
1553
|
+
if (startDate.startsWith("--")) {
|
|
1554
|
+
String[] parts = startDate.substring(2).split("-");
|
|
1555
|
+
if (parts.length >= 2) {
|
|
1556
|
+
birthdayMonth = safeParse(parts[0]);
|
|
1557
|
+
birthdayDay = safeParse(parts[1]);
|
|
1558
|
+
}
|
|
1559
|
+
} else {
|
|
1560
|
+
// Standard format: YYYY-MM-DD
|
|
1561
|
+
String[] parts = startDate.split("-");
|
|
1562
|
+
if (parts.length >= 3) {
|
|
1563
|
+
birthdayYear = safeParse(parts[0]);
|
|
1564
|
+
birthdayMonth = safeParse(parts[1]);
|
|
1565
|
+
birthdayDay = safeParse(parts[2]);
|
|
1566
|
+
}
|
|
1391
1567
|
}
|
|
1392
1568
|
}
|
|
1393
1569
|
|
|
1394
1570
|
JSObject toJSObject() {
|
|
1571
|
+
return toJSObject(null);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
JSObject toJSObject(Set<String> fields) {
|
|
1575
|
+
boolean includeAll = fields == null;
|
|
1395
1576
|
JSObject contact = new JSObject();
|
|
1396
|
-
|
|
1397
|
-
contact.put("
|
|
1398
|
-
contact.put("
|
|
1399
|
-
contact.put("
|
|
1400
|
-
contact.put("
|
|
1401
|
-
contact.put("
|
|
1402
|
-
contact.put("
|
|
1403
|
-
contact.put("
|
|
1404
|
-
contact.put("
|
|
1405
|
-
contact.put("
|
|
1406
|
-
contact.put("
|
|
1407
|
-
contact.put("
|
|
1408
|
-
contact.put("
|
|
1409
|
-
contact.put("
|
|
1410
|
-
contact.put("
|
|
1411
|
-
contact.put("
|
|
1412
|
-
|
|
1413
|
-
|
|
1577
|
+
|
|
1578
|
+
if (includeAll || fields.contains("id")) contact.put("id", id);
|
|
1579
|
+
if (includeAll || fields.contains("givenName")) contact.put("givenName", givenName);
|
|
1580
|
+
if (includeAll || fields.contains("familyName")) contact.put("familyName", familyName);
|
|
1581
|
+
if (includeAll || fields.contains("middleName")) contact.put("middleName", middleName);
|
|
1582
|
+
if (includeAll || fields.contains("namePrefix")) contact.put("namePrefix", namePrefix);
|
|
1583
|
+
if (includeAll || fields.contains("nameSuffix")) contact.put("nameSuffix", nameSuffix);
|
|
1584
|
+
if (includeAll || fields.contains("organizationName")) contact.put("organizationName", organizationName);
|
|
1585
|
+
if (includeAll || fields.contains("jobTitle")) contact.put("jobTitle", jobTitle);
|
|
1586
|
+
if (includeAll || fields.contains("note")) contact.put("note", note);
|
|
1587
|
+
if (includeAll || fields.contains("fullName")) contact.put("fullName", fullName);
|
|
1588
|
+
if (includeAll || fields.contains("photo")) contact.put("photo", photoBase64);
|
|
1589
|
+
if (includeAll || fields.contains("groupIds")) contact.put("groupIds", groupIds);
|
|
1590
|
+
if (includeAll || fields.contains("emailAddresses")) contact.put("emailAddresses", emailAddresses);
|
|
1591
|
+
if (includeAll || fields.contains("phoneNumbers")) contact.put("phoneNumbers", phoneNumbers);
|
|
1592
|
+
if (includeAll || fields.contains("postalAddresses")) contact.put("postalAddresses", postalAddresses);
|
|
1593
|
+
if (includeAll || fields.contains("urlAddresses")) contact.put("urlAddresses", urlAddresses);
|
|
1594
|
+
|
|
1595
|
+
if ((includeAll || fields.contains("birthday")) && (birthdayYear != null || birthdayMonth != null || birthdayDay != null)) {
|
|
1414
1596
|
JSObject birthday = new JSObject();
|
|
1415
1597
|
if (birthdayDay != null) birthday.put("day", birthdayDay);
|
|
1416
1598
|
if (birthdayMonth != null) birthday.put("month", birthdayMonth);
|
|
@@ -1418,13 +1600,15 @@ public class CapacitorContactsPlugin extends Plugin {
|
|
|
1418
1600
|
contact.put("birthday", birthday);
|
|
1419
1601
|
}
|
|
1420
1602
|
|
|
1421
|
-
if (
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1603
|
+
if (includeAll || fields.contains("account")) {
|
|
1604
|
+
if (accountName != null || accountType != null) {
|
|
1605
|
+
JSObject account = new JSObject();
|
|
1606
|
+
account.put("name", accountName);
|
|
1607
|
+
account.put("type", accountType);
|
|
1608
|
+
contact.put("account", account);
|
|
1609
|
+
} else {
|
|
1610
|
+
contact.put("account", null);
|
|
1611
|
+
}
|
|
1428
1612
|
}
|
|
1429
1613
|
|
|
1430
1614
|
return contact;
|
|
@@ -5,7 +5,7 @@ import UIKit
|
|
|
5
5
|
|
|
6
6
|
@objc(CapacitorContactsPlugin)
|
|
7
7
|
public class CapacitorContactsPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
8
|
-
private let pluginVersion: String = "8.0.
|
|
8
|
+
private let pluginVersion: String = "8.0.5"
|
|
9
9
|
public let identifier = "CapacitorContactsPlugin"
|
|
10
10
|
public let jsName = "CapacitorContacts"
|
|
11
11
|
public let pluginMethods: [CAPPluginMethod] = [
|