|
| 1 | +#nullable enable |
| 2 | + |
| 3 | +using System; |
| 4 | +using System.Collections.Generic; |
| 5 | +using System.Threading.Tasks; |
| 6 | +using Android.App; |
| 7 | +using Android.Content; |
| 8 | +using Android.Database; |
| 9 | +using Android.Provider; |
| 10 | +using Uno.Extensions; |
| 11 | +using Uno.Helpers.Activities; |
| 12 | +using Uno.UI; |
| 13 | +using Windows.Extensions; |
| 14 | + |
| 15 | +namespace Windows.ApplicationModel.Contacts |
| 16 | +{ |
| 17 | + public partial class ContactPicker |
| 18 | + { |
| 19 | + private static Task<bool> IsSupportedTaskAsync() => Task.FromResult(true); |
| 20 | + |
| 21 | + private async Task<Contact?> PickContactTaskAsync() |
| 22 | + { |
| 23 | + if (!await PermissionsHelper.CheckReadContactsPermission(default)) |
| 24 | + { |
| 25 | + if (!await PermissionsHelper.TryGetReadContactsPermission(default)) |
| 26 | + { |
| 27 | + throw new InvalidOperationException("android.permission.READ_CONTACTS permission is required"); |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + if (ContextHelper.Current == null) |
| 32 | + { |
| 33 | + throw new InvalidOperationException("Context is not initialized yet, API called too early in application lifecycle."); |
| 34 | + } |
| 35 | + |
| 36 | + using var intent = new Intent(Intent.ActionPick); |
| 37 | + intent.SetType(ContactsContract.CommonDataKinds.Phone.ContentType); |
| 38 | + var activity = await AwaitableResultActivity.StartAsync(); |
| 39 | + var result = await activity.StartActivityForResultAsync(intent); |
| 40 | + |
| 41 | + if (result?.Intent?.Data is Android.Net.Uri contactUri) |
| 42 | + { |
| 43 | + using var contentResolver = Application.Context.ContentResolver; |
| 44 | + if (contentResolver != null) |
| 45 | + { |
| 46 | + var projection = new string[] { ContactsContract.ContactsColumns.LookupKey }; |
| 47 | + using ICursor? cursorLookUpKey = contentResolver.Query(contactUri, projection, null, null, null); |
| 48 | + if (cursorLookUpKey?.MoveToFirst() == true) |
| 49 | + { |
| 50 | + var lookupKey = cursorLookUpKey.GetString(cursorLookUpKey.GetColumnIndex(projection[0])); |
| 51 | + if (lookupKey != null) |
| 52 | + { |
| 53 | + return LookupToContact(lookupKey, contentResolver); |
| 54 | + } |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + return null; |
| 59 | + } |
| 60 | + |
| 61 | + private static Contact LookupToContact(string lookupKey, ContentResolver contentResolver) |
| 62 | + { |
| 63 | + var contact = new Contact(); |
| 64 | + |
| 65 | + |
| 66 | + ReadStructuredName(contact, lookupKey, contentResolver); |
| 67 | + |
| 68 | + //var displayName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.Contacts.InterfaceConsts.DisplayName)); |
| 69 | + //if (contact.DisplayName != displayName) |
| 70 | + //{ |
| 71 | + // contact.DisplayNameOverride = displayName ?? string.Empty; |
| 72 | + //} |
| 73 | + |
| 74 | + //contact.Notes = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Note.ContentItemType)) ?? string.Empty; |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | + //contact.Phones.AddRange(GetPhones(idQuery, contentResolver)); |
| 81 | + |
| 82 | + //contact.Emails.AddRange(GetEmails(idQuery, contentResolver)); |
| 83 | + |
| 84 | + //contact.Addresses.AddRange(GetAddresses(idQuery, contentResolver)); |
| 85 | + |
| 86 | + return contact; |
| 87 | + } |
| 88 | + |
| 89 | + private static void ReadStructuredName(Contact contact, string lookupKey, ContentResolver contentResolver) |
| 90 | + { |
| 91 | + var contactWhere = ContactsContract.ContactsColumns.LookupKey + " = ?"; |
| 92 | + var contactWhereParams = new[] { lookupKey }; |
| 93 | + if (ContactsContract.Data.ContentUri != null) |
| 94 | + { |
| 95 | + using var cursor = contentResolver.Query( |
| 96 | + ContactsContract.Data.ContentUri, |
| 97 | + null, |
| 98 | + contactWhere, |
| 99 | + contactWhereParams, |
| 100 | + null |
| 101 | + ); |
| 102 | + if (cursor?.MoveToFirst() == true) |
| 103 | + { |
| 104 | + contact.HonorificNamePrefix = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.Prefix)) ?? string.Empty; |
| 105 | + contact.FirstName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GivenName)) ?? string.Empty; |
| 106 | + contact.MiddleName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MiddleName)) ?? string.Empty; |
| 107 | + contact.LastName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FamilyName)) ?? string.Empty; |
| 108 | + contact.HonorificNameSuffix = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.Suffix)) ?? string.Empty; |
| 109 | + |
| 110 | + contact.YomiGivenName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.PhoneticGivenName)) ?? string.Empty; |
| 111 | + contact.YomiFamilyName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredName.PhoneticFamilyName)) ?? string.Empty; |
| 112 | + } |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + private static IEnumerable<ContactPhone> GetPhones(string[] idQuery, ContentResolver contentResolver) |
| 117 | + { |
| 118 | + var contactPhones = new List<ContactPhone>(); |
| 119 | + var uri = ContactsContract.CommonDataKinds.Phone.ContentUri?.BuildUpon()?.AppendQueryParameter(ContactsContract.RemoveDuplicateEntries, "1")?.Build(); |
| 120 | + |
| 121 | + if (uri != null) |
| 122 | + { |
| 123 | + using ICursor? cursor = contentResolver.Query( |
| 124 | + uri, |
| 125 | + null, |
| 126 | + ContactsContract.Contacts.InterfaceConsts.Id + "=?", |
| 127 | + idQuery, |
| 128 | + null); |
| 129 | + |
| 130 | + if (cursor != null) |
| 131 | + { |
| 132 | + if (cursor.MoveToFirst()) |
| 133 | + { |
| 134 | + do |
| 135 | + { |
| 136 | + var number = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Phone.Number)); |
| 137 | + |
| 138 | + var phoneType = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Phone.InterfaceConsts.Type)); |
| 139 | + var kind = TypeToContactPhoneKind(phoneType); |
| 140 | + |
| 141 | + contactPhones.Add(new ContactPhone() |
| 142 | + { |
| 143 | + Kind = kind, |
| 144 | + Number = number ?? string.Empty |
| 145 | + }); |
| 146 | + } |
| 147 | + while (cursor.MoveToNext()); |
| 148 | + } |
| 149 | + cursor.Close(); |
| 150 | + } |
| 151 | + } |
| 152 | + return contactPhones; |
| 153 | + } |
| 154 | + |
| 155 | + private static IEnumerable<ContactEmail> GetEmails(string[] idQuery, ContentResolver contentResolver) |
| 156 | + { |
| 157 | + var contactEmails = new List<ContactEmail>(); |
| 158 | + var uri = ContactsContract.CommonDataKinds.Email.ContentUri?.BuildUpon()?.AppendQueryParameter(ContactsContract.RemoveDuplicateEntries, "1")?.Build(); |
| 159 | + |
| 160 | + if (uri != null) |
| 161 | + { |
| 162 | + using ICursor? cursor = contentResolver.Query( |
| 163 | + uri, |
| 164 | + null, |
| 165 | + ContactsContract.Contacts.InterfaceConsts.Id + "=?", |
| 166 | + idQuery, |
| 167 | + null); |
| 168 | + |
| 169 | + if (cursor != null) |
| 170 | + { |
| 171 | + if (cursor.MoveToFirst()) |
| 172 | + { |
| 173 | + do |
| 174 | + { |
| 175 | + var address = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Email.Address)); |
| 176 | + |
| 177 | + var emailType = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Email.InterfaceConsts.Type)); |
| 178 | + var kind = TypeToContactEmailKind(emailType); |
| 179 | + |
| 180 | + contactEmails.Add(new ContactEmail() |
| 181 | + { |
| 182 | + Kind = kind, |
| 183 | + Address = address ?? string.Empty |
| 184 | + }); |
| 185 | + } |
| 186 | + while (cursor.MoveToNext()); |
| 187 | + } |
| 188 | + cursor.Close(); |
| 189 | + } |
| 190 | + } |
| 191 | + return contactEmails; |
| 192 | + } |
| 193 | + |
| 194 | + private static IEnumerable<ContactAddress> GetAddresses(string[] idQuery, ContentResolver contentResolver) |
| 195 | + { |
| 196 | + var contactAddresss = new List<ContactAddress>(); |
| 197 | + var uri = ContactsContract.CommonDataKinds.StructuredPostal.ContentUri?.BuildUpon()?.AppendQueryParameter(ContactsContract.RemoveDuplicateEntries, "1")?.Build(); |
| 198 | + |
| 199 | + if (uri != null) |
| 200 | + { |
| 201 | + using ICursor? cursor = contentResolver.Query( |
| 202 | + uri, |
| 203 | + null, |
| 204 | + ContactsContract.Contacts.InterfaceConsts.Id + "=?", |
| 205 | + idQuery, |
| 206 | + null); |
| 207 | + |
| 208 | + if (cursor != null) |
| 209 | + { |
| 210 | + if (cursor.MoveToFirst()) |
| 211 | + { |
| 212 | + do |
| 213 | + { |
| 214 | + var city = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.City)); |
| 215 | + var country = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.Country)); |
| 216 | + var postalCode = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.Postcode)); |
| 217 | + var region = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.Region)); |
| 218 | + var street = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.Street)); |
| 219 | + |
| 220 | + var addressType = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.InterfaceConsts.Type)); |
| 221 | + var kind = TypeToContactAddressKind(addressType); |
| 222 | + |
| 223 | + contactAddresss.Add(new ContactAddress() |
| 224 | + { |
| 225 | + Kind = kind, |
| 226 | + Country = country ?? string.Empty, |
| 227 | + Locality = city ?? string.Empty, |
| 228 | + PostalCode = postalCode ?? string.Empty, |
| 229 | + Region = region ?? string.Empty, |
| 230 | + StreetAddress = street ?? string.Empty |
| 231 | + }); |
| 232 | + } |
| 233 | + while (cursor.MoveToNext()); |
| 234 | + } |
| 235 | + cursor.Close(); |
| 236 | + } |
| 237 | + } |
| 238 | + return contactAddresss; |
| 239 | + } |
| 240 | + |
| 241 | + private static ContactPhoneKind TypeToContactPhoneKind(string? type) |
| 242 | + { |
| 243 | + if (int.TryParse(type, out var typeInt)) |
| 244 | + { |
| 245 | + if (Enum.IsDefined(typeof(PhoneDataKind), typeInt)) |
| 246 | + { |
| 247 | + var PhoneType = (PhoneDataKind)typeInt; |
| 248 | + return PhoneType switch |
| 249 | + { |
| 250 | + PhoneDataKind.Assistant => ContactPhoneKind.Assistant, |
| 251 | + PhoneDataKind.CompanyMain => ContactPhoneKind.Company, |
| 252 | + PhoneDataKind.Main => ContactPhoneKind.Mobile, |
| 253 | + PhoneDataKind.Mobile => ContactPhoneKind.Mobile, |
| 254 | + PhoneDataKind.Home => ContactPhoneKind.Home, |
| 255 | + PhoneDataKind.FaxHome => ContactPhoneKind.HomeFax, |
| 256 | + PhoneDataKind.Pager => ContactPhoneKind.Pager, |
| 257 | + PhoneDataKind.Radio => ContactPhoneKind.Radio, |
| 258 | + PhoneDataKind.Work => ContactPhoneKind.Work, |
| 259 | + PhoneDataKind.WorkMobile => ContactPhoneKind.Work, |
| 260 | + PhoneDataKind.WorkPager => ContactPhoneKind.Work, |
| 261 | + PhoneDataKind.FaxWork => ContactPhoneKind.BusinessFax, |
| 262 | + _ => ContactPhoneKind.Other |
| 263 | + }; |
| 264 | + } |
| 265 | + } |
| 266 | + return ContactPhoneKind.Other; |
| 267 | + } |
| 268 | + |
| 269 | + private static ContactEmailKind TypeToContactEmailKind(string? type) |
| 270 | + { |
| 271 | + if (int.TryParse(type, out var typeInt)) |
| 272 | + { |
| 273 | + if (Enum.IsDefined(typeof(EmailDataKind), typeInt)) |
| 274 | + { |
| 275 | + var EmailType = (EmailDataKind)typeInt; |
| 276 | + return EmailType switch |
| 277 | + { |
| 278 | + EmailDataKind.Home => ContactEmailKind.Personal, |
| 279 | + EmailDataKind.Mobile => ContactEmailKind.Personal, |
| 280 | + EmailDataKind.Work => ContactEmailKind.Work, |
| 281 | + _ => ContactEmailKind.Other |
| 282 | + }; |
| 283 | + } |
| 284 | + } |
| 285 | + return ContactEmailKind.Other; |
| 286 | + } |
| 287 | + |
| 288 | + private static ContactAddressKind TypeToContactAddressKind(string? type) |
| 289 | + { |
| 290 | + if (int.TryParse(type, out var typeInt)) |
| 291 | + { |
| 292 | + if (Enum.IsDefined(typeof(AddressDataKind), typeInt)) |
| 293 | + { |
| 294 | + var addressType = (AddressDataKind)typeInt; |
| 295 | + return addressType switch |
| 296 | + { |
| 297 | + AddressDataKind.Home => ContactAddressKind.Home, |
| 298 | + AddressDataKind.Work => ContactAddressKind.Work, |
| 299 | + _ => ContactAddressKind.Other |
| 300 | + }; |
| 301 | + } |
| 302 | + } |
| 303 | + return ContactAddressKind.Other; |
| 304 | + } |
| 305 | + } |
| 306 | +} |
0 commit comments