From 76da97acfc9d7c5c71c43737c32b4de11fe142cd Mon Sep 17 00:00:00 2001 From: REIS Benjamin Date: Thu, 13 Oct 2016 11:51:06 +0200 Subject: [PATCH] Update dynamically adress book, linphoneImahe on valid sip address or phone number in contact detail --- Classes/ContactsListTableView.m | 9 +++ Classes/LinphoneAppDelegate.m | 15 ++++ Classes/LinphoneManager.m | 3 +- .../Base.lproj/UIContactDetailsCell.xib | 44 +++++++---- Classes/LinphoneUI/UIContactCell.m | 13 ++-- Classes/LinphoneUI/UIContactDetailsCell.h | 1 + Classes/LinphoneUI/UIContactDetailsCell.m | 8 ++ Classes/Utils/FastAddressBook.h | 2 + Classes/Utils/FastAddressBook.m | 75 +++++++++++++++++-- 9 files changed, 141 insertions(+), 29 deletions(-) diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index d02b6e319..a4038e42c 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -113,6 +113,15 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { - (void)loadData { LOGI(@"Load contact list"); @synchronized(addressBookMap) { + //Set all contacts from ContactCell to nil + for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j) + { + for (NSInteger i = 0; i < [self.tableView numberOfRowsInSection:j]; ++i) + { + [[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]] setContact:nil]; + } + } + // Reset Address book [addressBookMap removeAllObjects]; diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index b446852a4..cbdd9329d 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -18,6 +18,7 @@ */ #import "PhoneMainView.h" +#import "ContactsListView.h" #import "ShopView.h" #import "linphoneAppDelegate.h" #import "AddressBook/ABPerson.h" @@ -87,6 +88,20 @@ LinphoneManager *instance = LinphoneManager.instance; [instance becomeActive]; + + if (instance.fastAddressBook.needToUpdate) { + //Update address book for external changes + if (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription) { + [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; + } + [instance.fastAddressBook reload]; + instance.fastAddressBook.needToUpdate = FALSE; + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + linphone_friend_list_update_subscriptions(lists->data); + lists = lists->next; + } + } LinphoneCall *call = linphone_core_get_current_call(LC); diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index d544d4441..e6e4376a5 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -43,6 +43,8 @@ #import #import "Utils.h" #import "PhoneMainView.h" +#import "ChatsListView.h" +#import "ChatConversationView.h" #import #define LINPHONE_LOGS_MAX_ENTRY 5000 @@ -1217,7 +1219,6 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, const char }]; } } - // Post event NSDictionary *dict = @{ @"room" : [NSValue valueWithPointer:room], diff --git a/Classes/LinphoneUI/Base.lproj/UIContactDetailsCell.xib b/Classes/LinphoneUI/Base.lproj/UIContactDetailsCell.xib index 7ccaeab36..f695afd8c 100644 --- a/Classes/LinphoneUI/Base.lproj/UIContactDetailsCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIContactDetailsCell.xib @@ -1,8 +1,9 @@ - + - + + @@ -14,6 +15,7 @@ + @@ -22,23 +24,23 @@ - + - + - + - + - + + + + + - + @@ -104,5 +110,11 @@ + + + + + + diff --git a/Classes/LinphoneUI/UIContactCell.m b/Classes/LinphoneUI/UIContactCell.m index d8949f1e0..0b96045e6 100644 --- a/Classes/LinphoneUI/UIContactCell.m +++ b/Classes/LinphoneUI/UIContactCell.m @@ -61,8 +61,10 @@ - (void)onPresenceChanged:(NSNotification *)k { LinphoneFriend *f = [[k.userInfo valueForKey:@"friend"] pointerValue]; // only consider event if it's about us - if (!_contact.friend || f != _contact.friend) { - return; + if (_contact) { + if (!_contact.friend || f != _contact.friend) { + return; + } } [self setContact:_contact]; } @@ -71,9 +73,10 @@ - (void)setContact:(Contact *)acontact { _contact = acontact; - - [ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact]; - _linphoneImage.hidden = ! (_contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(_contact.friend)) == LinphonePresenceBasicStatusOpen); + if(_contact) { + [ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact]; + _linphoneImage.hidden = ! (_contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(_contact.friend)) == LinphonePresenceBasicStatusOpen); + } } #pragma mark - diff --git a/Classes/LinphoneUI/UIContactDetailsCell.h b/Classes/LinphoneUI/UIContactDetailsCell.h index e97b42529..03969d632 100644 --- a/Classes/LinphoneUI/UIContactDetailsCell.h +++ b/Classes/LinphoneUI/UIContactDetailsCell.h @@ -34,6 +34,7 @@ @property(weak, nonatomic) IBOutlet UIIconButton *deleteButton; @property(weak, nonatomic) IBOutlet UIIconButton *callButton; @property(weak, nonatomic) IBOutlet UIIconButton *chatButton; +@property (weak, nonatomic) IBOutlet UIImageView *linphoneImage; - (id)initWithIdentifier:(NSString *)identifier; - (void)setAddress:(NSString *)address; diff --git a/Classes/LinphoneUI/UIContactDetailsCell.m b/Classes/LinphoneUI/UIContactDetailsCell.m index bc1a2d4f2..f178b8ce0 100644 --- a/Classes/LinphoneUI/UIContactDetailsCell.m +++ b/Classes/LinphoneUI/UIContactDetailsCell.m @@ -18,6 +18,8 @@ */ #import "UIContactDetailsCell.h" +#import "FastAddressBook.h" +#import "Contact.h" #import "PhoneMainView.h" @implementation UIContactDetailsCell @@ -48,6 +50,12 @@ _chatButton.accessibilityLabel = [NSString stringWithFormat:NSLocalizedString(@"Chat with %@", nil), _addressLabel.text]; _callButton.accessibilityLabel = [NSString stringWithFormat:NSLocalizedString(@"Call %@", nil), _addressLabel.text]; + // Test presence + Contact* contact = [FastAddressBook getContactWithAddress:(addr)]; + if (contact) { + self.linphoneImage.hidden = ! ((contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model_for_uri_or_tel(contact.friend, _addressLabel.text.UTF8String)) == LinphonePresenceBasicStatusOpen) || (!linphone_proxy_config_is_phone_number(linphone_core_get_default_proxy_config(LC), _addressLabel.text.UTF8String) && [FastAddressBook isSipURIValid:_addressLabel.text])); + } + if (addr) { linphone_address_destroy(addr); } diff --git a/Classes/Utils/FastAddressBook.h b/Classes/Utils/FastAddressBook.h index 72e462e63..6267bff55 100644 --- a/Classes/Utils/FastAddressBook.h +++ b/Classes/Utils/FastAddressBook.h @@ -26,6 +26,7 @@ @interface FastAddressBook : NSObject @property(readonly, nonatomic) NSMutableDictionary *addressBookMap; +@property BOOL needToUpdate; - (void)reload; - (void)saveAddressBook; @@ -42,6 +43,7 @@ + (UIImage *)imageForAddress:(const LinphoneAddress *)addr thumbnail:(BOOL)thumbnail; + (BOOL)contactHasValidSipDomain:(Contact *)person; ++ (BOOL)isSipURIValid:(NSString*)addr; + (NSString *)displayNameForContact:(Contact *)person; + (NSString *)displayNameForAddress:(const LinphoneAddress *)addr; diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index bfb57bbde..b732151f5 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -16,7 +16,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +#ifdef __IPHONE_9_0 +#import +#endif #import "FastAddressBook.h" #import "LinphoneManager.h" #import "ContactsListView.h" @@ -24,6 +26,7 @@ @implementation FastAddressBook { ABAddressBookRef addressBook; + CNContactStore* store; } static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context); @@ -95,6 +98,39 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info addressBook = nil; [self reload]; } + self.needToUpdate = FALSE; + if ([CNContactStore class]) { + //ios9 or later + CNEntityType entityType = CNEntityTypeContacts; + if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined) { + CNContactStore * contactStore = [[CNContactStore alloc] init]; + [contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) { + if(granted){ + NSError* contactError; + store = [[CNContactStore alloc]init]; + [store containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers: @[store.defaultContainerIdentifier]] error:&contactError]; + NSArray * keysToFetch =@[CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPostalAddressesKey]; + CNContactFetchRequest * request = [[CNContactFetchRequest alloc]initWithKeysToFetch:keysToFetch]; + BOOL success = [store enumerateContactsWithFetchRequest:request error:&contactError usingBlock:^(CNContact * __nonnull contact, BOOL * __nonnull stop){}]; + if(success) { + LOGD(@"CNContactStore successfully synchronized"); + } + } + }]; + } else if([CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized) { + NSError* contactError; + store = [[CNContactStore alloc]init]; + [store containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers: @[store.defaultContainerIdentifier]] error:&contactError]; + NSArray * keysToFetch =@[CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPostalAddressesKey]; + CNContactFetchRequest * request = [[CNContactFetchRequest alloc]initWithKeysToFetch:keysToFetch]; + BOOL success = [store enumerateContactsWithFetchRequest:request error:&contactError usingBlock:^(CNContact * __nonnull contact, BOOL * __nonnull stop){}]; + if(success) { + LOGD(@"CNContactStore successfully synchronized"); + } + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil]; + } + return self; } @@ -117,13 +153,13 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info if (addressBook != nil) { __weak FastAddressBook *weakSelf = self; ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { - if (!granted) { - LOGE(@"Permission for address book acces was denied: %@", [(__bridge NSError *)error description]); - return; - } + if (!granted) { + LOGE(@"Permission for address book acces was denied: %@", [(__bridge NSError *)error description]); + return; + } - ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(weakSelf)); - [weakSelf loadData]; + ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(weakSelf)); + [weakSelf loadData]; }); } else { @@ -131,6 +167,11 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info } } +-(void) updateAddressBook:(NSNotification*) notif { + LOGD(@"address book has changed"); + self.needToUpdate = TRUE; +} + - (void)registerAddrsFor:(Contact *)contact { for (NSString *phone in contact.phoneNumbers) { char *normalizedPhone = @@ -177,6 +218,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info } friends = friends->next; } + linphone_friend_list_update_subscriptions(fl); lists = lists->next; } } @@ -228,6 +270,25 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void return NO; } ++ (BOOL) isSipURIValid:(NSString*)addr { + NSString *domain = LinphoneManager.instance.contactFilter; + LinphoneAddress* address = linphone_core_interpret_url(LC, addr.UTF8String); + if (address) { + const char *dom = linphone_address_get_domain(address); + BOOL match = false; + if (dom != NULL) { + NSString *contactDomain = [NSString stringWithCString:dom encoding:[NSString defaultCStringEncoding]]; + match = (([domain compare:@"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) || + ([domain compare:contactDomain options:NSCaseInsensitiveSearch] == NSOrderedSame)); + } + linphone_address_destroy(address); + if (match) { + return YES; + } + } + return NO; +} + + (NSString *)displayNameForContact:(Contact *)contact { return contact.displayName; }