Skip to content

Commit

Permalink
feat(ContactPicker): Pick single contact on Tizen
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Feb 4, 2021
1 parent 46c6f13 commit 2e32116
Show file tree
Hide file tree
Showing 5 changed files with 286 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#nullable enable

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Tizen.Applications;
using Tizen.Pims.Contacts;
using Windows.ApplicationModel.Contacts;
using Uno.UI.Runtime.Skia.Tizen.Helpers;
using System;
using TizenContact = Tizen.Pims.Contacts.ContactsViews.Contact;
using TizenEmail = Tizen.Pims.Contacts.ContactsViews.Email;
using TizenName = Tizen.Pims.Contacts.ContactsViews.Name;
using TizenNumber = Tizen.Pims.Contacts.ContactsViews.Number;
using TizenAddress = Tizen.Pims.Contacts.ContactsViews.Address;

namespace Uno.UI.Runtime.Skia.Tizen.ApplicationModel.Contacts
{
public class ContactPickerExtension : IContactPickerExtension
{
private const string ContactMimeType = "application/vnd.tizen.contact";

public Task<bool> IsSupportedAsync() => Task.FromResult(true);

public async Task<Contact?> PickContactAsync()
{
var results = await PickContactsAsync(false);
return results.FirstOrDefault();
}

private async Task<Contact[]> PickContactsAsync(bool pickMultiple)
{
if (!await PrivilegesHelper.RequestAsync(Privileges.ContactsRead))
{
return Array.Empty<Contact>();
}

var completionSource = new TaskCompletionSource<Contact[]>();

var appControl = new AppControl
{
Operation = AppControlOperations.Pick,
LaunchMode = AppControlLaunchMode.Single,
Mime = ContactMimeType
};
appControl.ExtraData.Add(AppControlData.SectionMode, pickMultiple ? "multiple" : "single");

AppControl.SendLaunchRequest(appControl, (request, reply, pickResult) =>
{
var results = new List<Contact>();
if (pickResult == AppControlReplyResult.Succeeded)
{
var contactsManager = new ContactsManager();
var pickedContacts = reply.ExtraData.Get<IEnumerable<string>>(AppControlData.Selected);
foreach (var pickedContactId in pickedContacts)
{
if (int.TryParse(pickedContactId, out var contactId))
{
var tizenContact = contactsManager.Database.Get(TizenContact.Uri, contactId);
if (tizenContact != null)
{
var contact = ContactFromContactsRecord(tizenContact);
results.Add(contact);
}
}
}
}
completionSource.TrySetResult(results.ToArray());
});

return await completionSource.Task;
}

private static Contact ContactFromContactsRecord(ContactsRecord contactsRecord)
{
var contact = new Contact();

var recordName = contactsRecord.GetChildRecord(TizenContact.Name, 0);
if (recordName != null)
{
contact.HonorificNamePrefix = recordName.Get<string>(TizenName.Prefix) ?? string.Empty;
contact.FirstName = recordName.Get<string>(TizenName.First) ?? string.Empty;
contact.MiddleName = recordName.Get<string>(TizenName.Addition) ?? string.Empty;
contact.LastName = recordName.Get<string>(TizenName.Last) ?? string.Empty;
contact.HonorificNameSuffix = recordName.Get<string>(TizenName.Suffix) ?? string.Empty;

contact.YomiGivenName = recordName.Get<string>(TizenName.PhoneticFirst) ?? string.Empty;
contact.YomiFamilyName = recordName.Get<string>(TizenName.PhoneticLast) ?? string.Empty;
}

var emailCount = contactsRecord.GetChildRecordCount(TizenContact.Email);
for (var mailId = 0; mailId < emailCount; mailId++)
{
var emailRecord = contactsRecord.GetChildRecord(TizenContact.Email, mailId);
var address = emailRecord.Get<string>(TizenEmail.Address);
var type = (TizenEmail.Types)emailRecord.Get<int>(TizenEmail.Type);

contact.Emails.Add(new ContactEmail()
{
Address = address,
Kind = GetContactEmailKind(type)
});
}

var phoneCount = contactsRecord.GetChildRecordCount(TizenContact.Number);
for (var phoneId = 0; phoneId < phoneCount; phoneId++)
{
var phoneRecord = contactsRecord.GetChildRecord(TizenContact.Number, phoneId);
var number = phoneRecord.Get<string>(TizenNumber.NumberData);
var type = (TizenNumber.Types)phoneRecord.Get<int>(TizenNumber.Type);

contact.Phones.Add(new ContactPhone()
{
Number = number,
Kind = GetContactPhoneKind(type)
});
}

var addressCount = contactsRecord.GetChildRecordCount(TizenContact.Address);
for (var addressId = 0; addressId < addressCount; addressId++)
{
var addressRecord = contactsRecord.GetChildRecord(TizenContact.Address, addressId);
var country = addressRecord.Get<string>(TizenAddress.Country);
var locality = addressRecord.Get<string>(TizenAddress.Locality);
var street = addressRecord.Get<string>(TizenAddress.Street);
var region = addressRecord.Get<string>(TizenAddress.Region);
var postalCode = addressRecord.Get<string>(TizenAddress.PostalCode);

var type = (TizenAddress.Types)addressRecord.Get<int>(TizenAddress.Type);

contact.Addresses.Add(new ContactAddress()
{
Country = country ?? string.Empty,
Locality = locality ?? string.Empty,
PostalCode = postalCode ?? string.Empty,
Region = region ?? string.Empty,
StreetAddress = street ?? string.Empty,
Kind = GetContactAddressKind(type)
});
}

return contact;
}

private static ContactEmailKind GetContactEmailKind(TizenEmail.Types emailType)
=> emailType switch
{
TizenEmail.Types.Home => ContactEmailKind.Personal,
TizenEmail.Types.Mobile => ContactEmailKind.Personal,
TizenEmail.Types.Work => ContactEmailKind.Work,
_ => ContactEmailKind.Other
};

private static ContactPhoneKind GetContactPhoneKind(TizenNumber.Types numberType)
=> numberType switch
{
TizenNumber.Types.Cell => ContactPhoneKind.Mobile,
TizenNumber.Types.Main => ContactPhoneKind.Mobile,
TizenNumber.Types.Home => ContactPhoneKind.Home,
TizenNumber.Types.Pager => ContactPhoneKind.Pager,
TizenNumber.Types.Assistant => ContactPhoneKind.Assistant,
TizenNumber.Types.Company => ContactPhoneKind.Company,
TizenNumber.Types.Fax => ContactPhoneKind.BusinessFax,
TizenNumber.Types.Radio => ContactPhoneKind.Radio,
_ => ContactPhoneKind.Other
};

private static ContactAddressKind GetContactAddressKind(TizenAddress.Types addressType) =>
addressType switch
{
TizenAddress.Types.Home => ContactAddressKind.Home,
TizenAddress.Types.Work => ContactAddressKind.Work,
_ => ContactAddressKind.Other
};
}
}
9 changes: 9 additions & 0 deletions src/Uno.UI.Runtime.Skia.Tizen/Tizen/Helpers/Privileges.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#nullable enable

namespace Uno.UI.Runtime.Skia.Tizen.Helpers
{
internal static class Privileges
{
internal const string ContactsRead = "http://tizen.org/privilege/contact.read";
}
}
54 changes: 54 additions & 0 deletions src/Uno.UI.Runtime.Skia.Tizen/Tizen/Helpers/PrivilegesHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#nullable enable

using System;
using System.Linq;
using System.Threading.Tasks;
using Tizen.Applications;
using Tizen.Security;

namespace Uno.UI.Runtime.Skia.Tizen.Helpers
{
internal class PrivilegesHelper
{
internal static void EnsureDeclared(string privilege)
{
var packageId = Application.Current.ApplicationInfo.PackageId;
var packageManager = PackageManager.GetPackage(packageId);

if (!packageManager.Privileges.Contains(privilege))
{
throw new InvalidOperationException($"Privilege {privilege} must be declared in the Tizen application manifest.");
}
}

internal static async Task<bool> RequestAsync(string privilege)
{
EnsureDeclared(privilege);

var checkResult = PrivacyPrivilegeManager.CheckPermission(privilege);
if (checkResult == CheckResult.Ask)
{
var completionSource = new TaskCompletionSource<bool>();
if (PrivacyPrivilegeManager.GetResponseContext(privilege).TryGetTarget(out var context))
{

void OnResponseFetched(object sender, RequestResponseEventArgs e)
{
completionSource.TrySetResult(e.result == RequestResult.AllowForever);
}
context.ResponseFetched += OnResponseFetched;
PrivacyPrivilegeManager.RequestPermission(privilege);
var result = await completionSource.Task;
context.ResponseFetched -= OnResponseFetched;
return true;
}
return false;
}
else if (checkResult == CheckResult.Deny)
{
return false;
}
return true;
}
}
}
41 changes: 41 additions & 0 deletions src/Uno.UWP/ApplicationModel/Contacts/ContactPicker.skia.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#nullable enable

using System.Threading.Tasks;
using Uno.Foundation.Extensibility;

namespace Windows.ApplicationModel.Contacts
{
public partial class ContactPicker
{
private static IContactPickerExtension? _contactPickerExtension;

static ContactPicker()
{
if (_contactPickerExtension == null)
{
ApiExtensibility.CreateInstance(typeof(ContactPicker), out _contactPickerExtension);
}
}

private static async Task<bool> IsSupportedTaskAsync()
{
return _contactPickerExtension != null && await _contactPickerExtension.IsSupportedAsync();
}

private async Task<Contact?> PickContactTaskAsync()
{
if (_contactPickerExtension != null)
{
return await _contactPickerExtension.PickContactAsync();
}
return null;
}
}

internal interface IContactPickerExtension
{
Task<bool> IsSupportedAsync();

Task<Contact?> PickContactAsync();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#if NET461 || __SKIA__ || __NETSTD_REFERENCE__
#if NET461 || __NETSTD_REFERENCE__
#nullable enable

namespace Windows.ApplicationModel.Contacts
{
public partial class ContactPicker
{
private static Task<bool> IsSupportedTaskAsync() => Task.FromResult(false);
private static Task<bool> IsSupportedTaskAsync => Task.FromResult(false);

private Task<Contact?> PickContactTaskAsync() => Task.FromResult<Contact?>(null);
}
Expand Down

0 comments on commit 2e32116

Please sign in to comment.