/* * PhoneGap is available under *either* the terms of the modified BSD license *or* the * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text. * * Copyright (c) 2005-2010, Nitobi Software Inc. * Copyright (c) 2010, IBM Corporation */ #import "Contacts.h" #import #import "PhoneGapDelegate.h" #import "Categories.h" #import "Notification.h" @implementation ContactsPicker @synthesize allowsEditing; @synthesize callbackId; @synthesize selectedId; @end @implementation NewContactsController @synthesize callbackId; @end @implementation DisplayContactsController @synthesize successCallback; @synthesize errorCallback; @end @implementation Contacts // no longer used since code gets AddressBook for each operation. // If address book changes during save or remove operation, may get error but not much we can do about it // If address book changes during UI creation, display or edit, we don't control any saves so no need for callback /*void addressBookChanged(ABAddressBookRef addressBook, CFDictionaryRef info, void* context) { // note that this function is only called when another AddressBook instance modifies // the address book, not the current one. For example, through an OTA MobileMe sync Contacts* contacts = (Contacts*)context; [contacts addressBookDirty]; }*/ -(PhoneGapCommand*) initWithWebView:(UIWebView*)theWebView { self = (Contacts*)[super initWithWebView:(UIWebView*)theWebView]; /*if (self) { addressBook = ABAddressBookCreate(); ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self); }*/ return self; } // overridden to clean up Contact statics -(void)onAppTerminate { NSLog(@"Contacts::onAppTerminate",0); [ Contact releaseDefaults]; } // iPhone only method to create a new contact through the GUI - (void) newContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; { NSString* callbackId = [arguments objectAtIndex:0]; NewContactsController* npController = [[[NewContactsController alloc] init] autorelease]; npController.addressBook = ABAddressBookCreate(); npController.newPersonViewDelegate = self; npController.callbackId = callbackId; UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:npController] autorelease]; [[super appViewController] presentModalViewController:navController animated: YES]; } - (void) newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person { ABRecordID recordId = kABRecordInvalidID; NewContactsController* newCP = (NewContactsController*) newPersonViewController; NSString* callbackId = newCP.callbackId; if (person != NULL) { //return the contact id recordId = ABRecordGetRecordID(person); } [newPersonViewController dismissModalViewControllerAnimated:YES]; PluginResult* result = [PluginResult resultWithStatus: PGCommandStatus_OK messageAsInt: recordId]; //jsString = [NSString stringWithFormat: @"%@(%d);", newCP.jsCallback, recordId]; [self writeJavascript: [result toSuccessCallbackString:callbackId]]; } - (void) displayContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { ABRecordID recordID = kABRecordInvalidID; NSString* callbackId = [arguments objectAtIndex:0]; recordID = [[arguments objectAtIndex:1] intValue]; //bool allowsEditing = [options isKindOfClass:[NSNull class]] ? false : [options existsValue:@"true" forKey:@"allowsEditing"]; ABAddressBookRef addrBook = ABAddressBookCreate(); ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID); if (rec) { ABPersonViewController* personController = [[[ABPersonViewController alloc] init] autorelease]; personController.displayedPerson = rec; personController.personViewDelegate = self; personController.allowsEditing = NO; //allowsEditing currently not supported UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target: self action: @selector(dismissModalView:)]; UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:personController] autorelease]; [[super appViewController] presentModalViewController:navController animated: YES]; // this needs to be AFTER presentModal, if not it does not show up (iOS 4 regression: workaround) personController.navigationItem.rightBarButtonItem = doneButton; [doneButton release]; CFRelease(rec); //Commented out code is various attempts to get editing // navigation working properly /*CGFloat width = webView.frame.size.width; UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0,0,width,52)]; navBar.autoresizingMask = UIViewAutoresizingFlexibleWidth; */ //[[super appNavController] pushViewController:personController animated: YES]; /*ContactsPicker* pickerController = [[[ContactsPicker alloc] init] autorelease]; pickerController.peoplePickerDelegate = self; */ //UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:personController] autorelease]; //UINavigationBar* navBar = navController.navigationBar; //NSLog(@"isNavBar == nil %d", (navBar == nil)); //[navBar setNavigationBarHidden: NO animated: NO]; //NSArray* navArray = [NSArray arrayWithObjects:pickerController, navController, nil]; //[navController setViewControllers: navArray animated: YES]; //[navController pushViewController:personController animated:NO]; //[navBar pushNavigationItem: doneButton animated:YES]; //UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:personController] autorelease]; //[navController pushViewController:personController animated:YES]; //personController.navigationItem.rightBarButtonItem = [navController editButtonItem]; } else { // no record, return error PluginResult* result = [PluginResult resultWithStatus: PGCommandStatus_OK messageAsInt: NOT_FOUND_ERROR]; [self writeJavascript:[result toErrorCallbackString:callbackId]]; } CFRelease(addrBook); } - (void) dismissModalView:(id)sender { UIViewController* controller = ([super appViewController]); [controller.modalViewController dismissModalViewControllerAnimated:YES]; } - (BOOL) personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue { return YES; } - (void) chooseContact:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { NSString* callbackId = [arguments objectAtIndex:0]; ContactsPicker* pickerController = [[[ContactsPicker alloc] init] autorelease]; pickerController.peoplePickerDelegate = self; pickerController.callbackId = callbackId; pickerController.selectedId = kABRecordInvalidID; pickerController.allowsEditing = (BOOL)[options existsValue:@"true" forKey:@"allowsEditing"]; [[super appViewController] presentModalViewController:pickerController animated: YES]; } - (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person { ContactsPicker* picker = (ContactsPicker*)peoplePicker; ABRecordID contactId = ABRecordGetRecordID(person); picker.selectedId = contactId; // save so can return when dismiss if (picker.allowsEditing) { ABPersonViewController* personController = [[[ABPersonViewController alloc] init] autorelease]; personController.displayedPerson = person; personController.personViewDelegate = self; personController.allowsEditing = picker.allowsEditing; [peoplePicker pushViewController:personController animated:YES]; } else { // return the contact Id PluginResult* result = [PluginResult resultWithStatus: PGCommandStatus_OK messageAsInt: contactId]; [self writeJavascript:[result toSuccessCallbackString: picker.callbackId]]; [picker dismissModalViewControllerAnimated:YES]; } return NO; } - (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { return YES; } - (void) peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { // return contactId or invalid if none picked ContactsPicker* picker = (ContactsPicker*)peoplePicker; PluginResult* result = [PluginResult resultWithStatus:PGCommandStatus_OK messageAsInt: picker.selectedId]; [self writeJavascript:[result toSuccessCallbackString:picker.callbackId]]; [peoplePicker dismissModalViewControllerAnimated:YES]; } - (void) search:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { NSString* jsString = nil; NSString* callbackId = [arguments objectAtIndex:0]; NSArray* fields = [options valueForKey:@"fields"]; NSDictionary* findOptions = [options valueForKey:@"findOptions"]; ABAddressBookRef addrBook = nil; NSArray* foundRecords = nil; addrBook = ABAddressBookCreate(); // get the findOptions values BOOL multiple = YES; // default is true //int limit = 1; // default if multiple is FALSE, will be set below if multiple is TRUE double msUpdatedSince = 0; BOOL bCheckDate = NO; NSString* filter = nil; BOOL bIncludeRecord = YES; if (![findOptions isKindOfClass:[NSNull class]]){ id value = nil; filter = (NSString*)[findOptions objectForKey:@"filter"]; value = [findOptions objectForKey:@"multiple"]; if ([value isKindOfClass:[NSNumber class]]){ // multiple is a boolean that will come through as an NSNumber multiple = [(NSNumber*)value boolValue]; //NSLog(@"multiple is: %d", multiple); } /* limit removed from Dec 2010 W3C contacts spec if (multiple == YES){ // we only care about limit if multiple is true value = [findOptions objectForKey:@"limit"]; if ([value isKindOfClass:[NSNumber class]]){ limit = [(NSNumber*)value intValue]; //NSLog(@"limit is: %d", limit); } else { // no limit specified, set it to -1 to get all limit = -1; } }*/ // see if there is an updated date id ms = [findOptions valueForKey:@"updatedSince"]; if (ms && [ms isKindOfClass:[NSNumber class]]){ msUpdatedSince = [ms doubleValue]; bCheckDate = YES; } } NSDictionary* returnFields = [[Contact class] calcReturnFields: fields]; NSMutableArray* matches = nil; if (!filter || [filter isEqualToString:@""]){ // get all records - use fields to determine what properties to return foundRecords = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook); if (foundRecords && [foundRecords count] > 0){ // create Contacts and put into matches array int xferCount = [foundRecords count]; matches = [NSMutableArray arrayWithCapacity:xferCount]; for(int k = 0; k 0){ // convert to JS Contacts format and return in callback NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; //int count = (limit > 0 ? MIN(limit,[matches count]) : [matches count]); int count = multiple == YES ? [matches count] : 1; for(int i = 0; i