Skip to content

Commit

Permalink
Merge remote-tracking branch 'github/develop' into github_master
Browse files Browse the repository at this point in the history
  • Loading branch information
weswmsft committed Aug 17, 2016
2 parents bff97aa + 00d7752 commit bfbf788
Show file tree
Hide file tree
Showing 305 changed files with 6,565 additions and 17,392 deletions.
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ BundleArtifacts/
[Oo]bj/
[Oo]SX/
*.o
*.UnitTests.exe

# Test results
tmp

# User-specific files
*.suo
*.swp
*.user
*.sln.docstates
*.lock.json
Expand All @@ -60,7 +60,7 @@ ehthumbs.db
Generated/
Generated Files/

# Ignore all CF public headers. They get copied in from the Frameworks directory as a pre build step.
# Ignore all CF public headers. They get copied in from the Frameworks directory as a pre build step.
Include/CoreFoundation/CFStream.h
Include/CoreFoundation/CFStringEncodingExt.h
Include/CoreFoundation/CoreFoundation.h
Expand Down Expand Up @@ -106,7 +106,7 @@ Include/CoreFoundation/CFData.h
Include/CoreFoundation/CFAttributedString.h
Include/CoreFoundation/module.modulemap

# Ignore all CF shared private headers. They get copied in from the Frameworks directory as a pre build step.
# Ignore all CF shared private headers. They get copied in from the Frameworks directory as a pre build step.
Frameworks/Include/ForFoundationOnly.h
Frameworks/Include/CFBundlePriv.h
Frameworks/Include/CFPriv.h
Expand Down
73 changes: 60 additions & 13 deletions Frameworks/AddressBook/ABAddressBook.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,91 @@

#import <AddressBook/ABAddressBook.h>

#import <StubReturn.h>
#import "AssertARCEnabled.h"
#import <StubReturn.h>
#import <Starboard/SmartTypes.h>

#import "ABAddressBookManagerInternal.h"

#import "UWP/InteropBase.h"
#import "UWP/WindowsDevicesEnumeration.h"
#import "initguid.h"

// GUID to check Windows Contacts permissions.
DEFINE_GUID(_ABAddressBookContactsGUID, 0x7D7E8402, 0x7C54, 0x4821, 0xA3, 0x4E, 0xAE, 0xEF, 0xD6, 0x2D, 0xED, 0x93);

const CFStringRef ABAddressBookErrorDomain = static_cast<const CFStringRef>(@"ABAddressBookErrorDomain");

/**
@Status Stub
@Status Interoperable
@Notes
*/
ABAddressBookRef ABAddressBookCreate() {
UNIMPLEMENTED();
return StubReturn();
return ABAddressBookCreateWithOptions(NULL, NULL);
}

/**
@Status Stub
@Status Interoperable
@Notes
*/
ABAddressBookRef ABAddressBookCreateWithOptions(CFDictionaryRef options, CFErrorRef* error) {
UNIMPLEMENTED();
return StubReturn();
_ABAddressBookManager* addressBook = [[_ABAddressBookManager alloc] init];
if (addressBook == nil) {
// There was an error setting up the backing
// contact store, so just return NULL to signify
// the error.
if (error != nullptr) {
// In this case, the caller is responsible to release error.
*error = CFErrorCreate(NULL, ABAddressBookErrorDomain, kABOperationNotPermittedByUserError, NULL);
}
return NULL;
} else {
return (__bridge_retained ABAddressBookRef)addressBook;
}
}

/**
@Status Stub
@Status Interoperable
@Notes
*/
ABAuthorizationStatus ABAddressBookGetAuthorizationStatus() {
UNIMPLEMENTED();
return kABAuthorizationStatusNotDetermined;
WFGUID* guid = [WFGUID guidWithGUID:_ABAddressBookContactsGUID];
WDEDeviceAccessInformation* deviceAccessInformation = [WDEDeviceAccessInformation createFromDeviceClassId:guid];
WDEDeviceAccessStatus currentStatus = deviceAccessInformation.currentStatus;

switch (currentStatus) {
case WDEDeviceAccessStatusAllowed:
return kABAuthorizationStatusAuthorized;
case WDEDeviceAccessStatusDeniedBySystem:
return kABAuthorizationStatusRestricted;
case WDEDeviceAccessStatusDeniedByUser:
return kABAuthorizationStatusDenied;
default: // WDEDeviceAccessStatusUnspecified:
return kABAuthorizationStatusNotDetermined;
}
}

/**
@Status Stub
@Notes
@Status Caveat
@Notes Requesting access should be done by declaring Contacts capabilities in the app's package manifest -- it cannot be granted at
runtime.
*/
void ABAddressBookRequestAccessWithCompletion(ABAddressBookRef addressBook, ABAddressBookRequestAccessCompletionHandler completion) {
UNIMPLEMENTED();
CFErrorRef error = nullptr;
bool accessGranted = ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized;
if (!accessGranted) {
error = CFErrorCreate(NULL, ABAddressBookErrorDomain, kABOperationNotPermittedByUserError, NULL);
}

// Since we can't request access at runtime (Contacts capabilities must be declared
// in the app's package manifest), immediately call the completion handler with the current
// authorization status. Dispatch it async to match the reference platform.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) {
woc::unique_cf<CFErrorRef> strongError;
strongError.reset(error);
completion(accessGranted, strongError.get());
});
}

/**
Expand Down
85 changes: 85 additions & 0 deletions Frameworks/AddressBook/ABAddressBookManagerInternal.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//******************************************************************************
//
// Copyright (c) 2016 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//******************************************************************************

#import "ABAddressBookManagerInternal.h"
#import "ABContactInternal.h"
#import "UWP/WindowsApplicationModelContacts.h"

@interface _ABAddressBookManager ()

@end

@implementation _ABAddressBookManager

- (id)init {
self = [super init];
if (self) {
__block WACContactStore* result = nil;
__block BOOL failed = YES;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

[WACContactManager requestStoreAsyncWithAccessType:WACContactStoreAccessTypeAllContactsReadOnly
success:^(WACContactStore* success) {
result = success;
failed = NO;
dispatch_semaphore_signal(semaphore);
}
failure:^(NSError* failure) {
failed = YES;
dispatch_semaphore_signal(semaphore);
}];

// Wait until async method completes.
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);

if (failed) {
return nil;
} else {
self.contactStore = result;
}
}

return self;
}

- (NSArray*)getListOfContacts {
__block NSMutableArray* result = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

[self.contactStore findContactsAsyncWithSuccess:^(NSArray* success) {
result = [NSMutableArray arrayWithCapacity:[success count]];

// Copy over the contacts wrapped in _ABContacts.
for (int i = 0; i < [success count]; i++) {
result[i] = [[_ABContact alloc] initWithContact:success[i]];
}

dispatch_semaphore_signal(semaphore);
}
failure:^(NSError* failure) {
// In the failure case, result will be nil.
dispatch_semaphore_signal(semaphore);
}];

// Wait until async method completes.
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);

return result;
}

@end
31 changes: 31 additions & 0 deletions Frameworks/AddressBook/ABContactInternal.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//******************************************************************************
//
// Copyright (c) 2016 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//******************************************************************************

#import "ABContactInternal.h"
#import "UWP/WindowsApplicationModelContacts.h"

@implementation _ABContact

- (id)initWithContact:(WACContact*)contact {
self = [super init];
if (self) {
self.contact = contact;
}

return self;
}

@end
65 changes: 56 additions & 9 deletions Frameworks/AddressBook/ABPerson.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#import <StubReturn.h>
#import "AssertARCEnabled.h"

#import "ABAddressBookManagerInternal.h"
#import "ABContactInternal.h"

const ABPropertyID kABPersonFirstNameProperty = 101;
const ABPropertyID kABPersonLastNameProperty = 102;
const ABPropertyID kABPersonMiddleNameProperty = 103;
Expand Down Expand Up @@ -200,30 +203,74 @@ bool ABPersonRemoveImageData(ABRecordRef person, CFErrorRef* error) {
}

/**
@Status Stub
@Status Interoperable
@Notes
*/
CFIndex ABAddressBookGetPersonCount(ABAddressBookRef addressBook) {
UNIMPLEMENTED();
return StubReturn();
if (addressBook == nullptr) {
return 0;
}
_ABAddressBookManager* addressBookManager = (__bridge _ABAddressBookManager*)addressBook;
NSArray* contacts = [addressBookManager getListOfContacts];
return [contacts count];
}

/**
@Status Stub
@Status Interoperable
@Notes
*/
ABRecordRef ABAddressBookGetPersonWithRecordID(ABAddressBookRef addressBook, ABRecordID recordID) {
UNIMPLEMENTED();
return StubReturn();
if (addressBook == nullptr) {
return nullptr;
}

_ABAddressBookManager* addressBookManager = (__bridge _ABAddressBookManager*)addressBook;

// An astute reader may notice that this method is slow for a user with many contacts,
// having to look through all of a user's contacts. Ideally, making use of
// a Windows method like GetContactAsync (which requires a String id) would happen, but the
// requirement of an ABRecordID being an int32_t forced this decision. A future version
// may choose to make ABRecordID a String if customers are willing to modify their code
// as needed for the added performance benefit.
NSArray* contacts = [addressBookManager getListOfContacts];
if (contacts == nil) {
return nullptr;
}

// Windows Contacts have their IDs as a string in the format:
// {storeid.itemtype.id}
// We are interested in the last part (id), we can just ensure
// that the ID ends with ".id}".
NSString* ending = [NSString stringWithFormat:@".%d}", recordID];
NSUInteger index = [contacts indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL* stop) {
_ABContact* person = (_ABContact*)obj;
if ([person.contact.id hasSuffix:ending]) {
*stop = YES;
return YES;
} else {
return NO;
}
}];

if (index == NSNotFound) {
return nullptr;
} else {
return (__bridge ABRecordRef)contacts[index];
}
}

/**
@Status Stub
@Status Interoperable
@Notes
*/
CFArrayRef ABAddressBookCopyArrayOfAllPeople(ABAddressBookRef addressBook) {
UNIMPLEMENTED();
return StubReturn();
if (addressBook == nullptr) {
return nullptr;
}

_ABAddressBookManager* addressBookManager = (__bridge _ABAddressBookManager*)addressBook;
NSArray* contacts = [addressBookManager getListOfContacts];
return (__bridge_retained CFArrayRef)contacts;
}

/**
Expand Down
Loading

0 comments on commit bfbf788

Please sign in to comment.