From 14f14e0113bf446fd73330d245f341990330a21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Turnel?= Date: Wed, 4 Oct 2017 15:16:26 +0200 Subject: [PATCH 01/42] Removed video bandwidth limit unless we are in custom mode --- Classes/LinphoneCoreSettingsStore.m | 13 +++---------- Resources/linphonerc | 4 +--- Resources/linphonerc-factory | 4 ++++ Resources/linphonerc~ipad | 2 -- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 012fac885..51909e9e1 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -722,34 +722,27 @@ NSString *videoPreset = [self stringForKey:@"video_preset_preference"]; linphone_core_set_video_preset(LC, [videoPreset UTF8String]); - int bw; MSVideoSize vsize; switch ([self integerForKey:@"video_preferred_size_preference"]) { case 0: MS_VIDEO_SIZE_ASSIGN(vsize, 720P); - // 128 = margin for audio, the BW includes both video and audio - bw = 1024 + 128; break; case 1: MS_VIDEO_SIZE_ASSIGN(vsize, VGA); - // no margin for VGA or QVGA, because video encoders can encode the - // target resulution in less than the asked bandwidth - bw = 660; break; case 2: default: MS_VIDEO_SIZE_ASSIGN(vsize, QVGA); - bw = 380; break; } linphone_core_set_preferred_video_size(LC, vsize); if (![videoPreset isEqualToString:@"custom"]) { [self setInteger:0 forKey:@"video_preferred_fps_preference"]; - [self setInteger:bw forKey:@"download_bandwidth_preference"]; + [self setInteger:0 forKey:@"download_bandwidth_preference"]; } linphone_core_set_preferred_framerate(LC, [self integerForKey:@"video_preferred_fps_preference"]); - linphone_core_set_download_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); - linphone_core_set_upload_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); + linphone_core_set_download_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); + linphone_core_set_upload_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); } // call section diff --git a/Resources/linphonerc b/Resources/linphonerc index e75cdba56..9fe2fff69 100644 --- a/Resources/linphonerc +++ b/Resources/linphonerc @@ -48,13 +48,11 @@ max_calls=3 real_early_media=1 [net] -download_bw=380 edge_bw=10 edge_ping_time=10 firewall_policy=ice mtu=1300 stun_server=stun.linphone.org -upload_bw=380 [rtp] audio_jitt_comp=60 @@ -93,5 +91,5 @@ capture=1 display=1 enabled=1 show_local=0 -size=qvga +size=vga diff --git a/Resources/linphonerc-factory b/Resources/linphonerc-factory index ff3807dcd..dfd3c1443 100644 --- a/Resources/linphonerc-factory +++ b/Resources/linphonerc-factory @@ -21,6 +21,10 @@ publish_presence=0 password_length=-1 username_length=-1 +[net] +download_bw=0 +upload_bw=0 + [sip] sip_random_port=0 #whether SIP passwords must be encrypted in configuration storage file diff --git a/Resources/linphonerc~ipad b/Resources/linphonerc~ipad index 965c48c1c..1eaec502d 100644 --- a/Resources/linphonerc~ipad +++ b/Resources/linphonerc~ipad @@ -22,13 +22,11 @@ file_transfer_server_url=https://www.linphone.org:444/lft.php max_calls=3 [net] -download_bw=512 edge_bw=10 edge_ping_time=10 firewall_policy=ice mtu=1300 stun_server=stun.linphone.org -upload_bw=512 [rtp] audio_jitt_comp=60 From 6e5d652dc2632b0cdee6ed85712d5eac86f40497 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 8 Oct 2017 10:08:02 +0200 Subject: [PATCH 02/42] update submodules (for ICE troubleshooting logs) --- submodules/linphone | 2 +- submodules/mediastreamer2 | 2 +- submodules/ortp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/linphone b/submodules/linphone index f975012e3..145b05ee8 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit f975012e3c2ef8a1511421a1e2816f33a54e6376 +Subproject commit 145b05ee8dddeca71518f327a69b474ac048f77a diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 6b78f9562..7666b7580 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6b78f95624660c4e1160c3caac74732250321ce1 +Subproject commit 7666b75803e8aa3df88183a40ec4f6b8a04f2018 diff --git a/submodules/ortp b/submodules/ortp index 90c00439f..5f8fcddce 160000 --- a/submodules/ortp +++ b/submodules/ortp @@ -1 +1 @@ -Subproject commit 90c00439f72ba5826f7d62d1fdc98d4a42752f8d +Subproject commit 5f8fcddce392f1510768949a4691f9e8c170badb From b087e61347b67e64d4c973a3196bd5bf843cfcdb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 8 Oct 2017 19:15:59 +0200 Subject: [PATCH 03/42] Update ms2 (fix audio issue with conference) --- submodules/mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 7666b7580..2f5f30e62 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7666b75803e8aa3df88183a40ec4f6b8a04f2018 +Subproject commit 2f5f30e62334ff00377f63f79235656632b23e89 From 0bbc6714d29b75f98240620e33a085fb2b6de728 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 10 Oct 2017 10:54:07 +0200 Subject: [PATCH 04/42] remove unecessary dependencies for now [Switch submodule branch] --- .gitmodules | 9 --------- submodules/cmake-builder | 2 +- submodules/externals/libxsd | 1 - submodules/externals/soci | 1 - submodules/externals/xerces-c | 1 - 5 files changed, 1 insertion(+), 13 deletions(-) delete mode 160000 submodules/externals/libxsd delete mode 160000 submodules/externals/soci delete mode 160000 submodules/externals/xerces-c diff --git a/.gitmodules b/.gitmodules index 1adc1677e..d4527eeb8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -111,12 +111,3 @@ [submodule "submodules/bcmatroska2"] path = submodules/bcmatroska2 url = git://git.linphone.org/bcmatroska2.git -[submodule "submodules/externals/soci"] - path = submodules/externals/soci - url = git://git.linphone.org/soci -[submodule "submodules/externals/xerces-c"] - path = submodules/externals/xerces-c - url = git://git.linphone.org/xerces-c -[submodule "submodules/externals/libxsd"] - path = submodules/externals/libxsd - url = git://git.linphone.org/libxsd diff --git a/submodules/cmake-builder b/submodules/cmake-builder index 99773d23d..1e93fee2d 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit 99773d23d71b78c75a8b2eb7ec91e7c3a69777f5 +Subproject commit 1e93fee2d0f72adb4e5a0b1ffeb422b84ab64618 diff --git a/submodules/externals/libxsd b/submodules/externals/libxsd deleted file mode 160000 index 97dfa5b7a..000000000 --- a/submodules/externals/libxsd +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 97dfa5b7af486a2730aa66ef4b2b04259c9ab21b diff --git a/submodules/externals/soci b/submodules/externals/soci deleted file mode 160000 index 908c7eb8f..000000000 --- a/submodules/externals/soci +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 908c7eb8f421601e6eb7b77e1131a35bcbe374fa diff --git a/submodules/externals/xerces-c b/submodules/externals/xerces-c deleted file mode 160000 index 9c15b9917..000000000 --- a/submodules/externals/xerces-c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9c15b9917507c584eadace89636b91af27b59b9c From 9307a25a5158a2dc3d55d9cf3eaf3497e37dfc0f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 13 Oct 2017 16:33:38 +0200 Subject: [PATCH 05/42] Decline incoming Call when CallKit returns DND --- Classes/LinphoneManager.m | 2 +- Classes/ProviderDelegate.h | 2 +- Classes/ProviderDelegate.m | 17 ++++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 2debfe0a2..fa3f3ed25 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -711,7 +711,7 @@ static void linphone_iphone_display_status(struct _LinphoneCore *lc, const char video = ([UIApplication sharedApplication].applicationState == UIApplicationStateActive && linphone_core_get_video_policy(LC)->automatically_accept && linphone_call_params_video_enabled(linphone_call_get_remote_params(call))); - [LinphoneManager.instance.providerDelegate reportIncomingCallwithUUID:uuid handle:address video:video]; + [LinphoneManager.instance.providerDelegate reportIncomingCall:call withUUID:uuid handle:address video:video]; #else [PhoneMainView.instance displayIncomingCall:call]; #endif diff --git a/Classes/ProviderDelegate.h b/Classes/ProviderDelegate.h index 488a4316e..964aac680 100644 --- a/Classes/ProviderDelegate.h +++ b/Classes/ProviderDelegate.h @@ -23,7 +23,7 @@ @property BOOL pendingCallVideo; @property int callKitCalls; -- (void)reportIncomingCallwithUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; +- (void)reportIncomingCall:(LinphoneCall *) call withUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; - (void)config; - (void)configAudioSession:(AVAudioSession *)audioSession; @end diff --git a/Classes/ProviderDelegate.m b/Classes/ProviderDelegate.m index 3479aaaee..6178d2f85 100644 --- a/Classes/ProviderDelegate.m +++ b/Classes/ProviderDelegate.m @@ -71,7 +71,7 @@ } } -- (void)reportIncomingCallwithUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video { +- (void)reportIncomingCall:(LinphoneCall *) call withUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; { // Create update to describe the incoming call and caller CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle]; @@ -80,13 +80,24 @@ update.supportsGrouping = TRUE; update.supportsUngrouping = TRUE; update.hasVideo = video; - + linphone_call_ref(call); // Report incoming call to system LOGD(@"CallKit: report new incoming call"); + [self.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError *error) { - }]; + if (error) { + LOGE(@"CallKit: cannot complete incoming call from [%@] caused by [%@]",handle,[error localizedDescription]); + if ( [error code] == CXErrorCodeIncomingCallErrorFilteredByDoNotDisturb + || [error code] == CXErrorCodeIncomingCallErrorFilteredByBlockList) { + linphone_call_decline(call,LinphoneReasonBusy); /*to give a chance for other devices to answer*/ + } else { + linphone_call_decline(call,LinphoneReasonUnknown); + } + } + linphone_call_unref(call); + }]; } - (void)setPendingCall:(LinphoneCall *)pendingCall { From 1a40291082cafb5bdb2978c58dbd72dc5d8d7d93 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 16 Oct 2017 10:18:35 +0200 Subject: [PATCH 06/42] update mediastreamer2 --- submodules/mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 2f5f30e62..0876afaf5 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2f5f30e62334ff00377f63f79235656632b23e89 +Subproject commit 0876afaf521161c83c20e64a1770ffe20359cbec From bd5e82865a703a81c36ee05205cec7d18bfcd19a Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 16 Oct 2017 10:38:12 +0200 Subject: [PATCH 07/42] remove unused link paths --- linphone.xcodeproj/project.pbxproj | 40 ++++++------------------------ 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 825d0dd55..9a4701fa0 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -828,14 +828,14 @@ remoteGlobalIDString = FAB8A0141CAC546A00C6DFC1; remoteInfo = KIFFrameworkConsumerTests; }; - 8CA26B4F1F7D31E700411264 /* PBXContainerItemProxy */ = { + 8C90F57A1F94A621003B86C4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; proxyType = 2; remoteGlobalIDString = 8CD87D4C1EF5105800ACA260; remoteInfo = LinphoneManager; }; - 8CA26B511F7D31E700411264 /* PBXContainerItemProxy */ = { + 8C90F57C1F94A621003B86C4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; proxyType = 2; @@ -2316,8 +2316,8 @@ 63058A071B4E816A00EFAE36 /* KIF.framework */, 633FC7C81CD7466400774B8B /* KIFFrameworkConsumer.app */, 633FC7CA1CD7466400774B8B /* KIFFrameworkConsumerTests.xctest */, - 8CA26B501F7D31E700411264 /* LinphoneManager.framework */, - 8CA26B521F7D31E700411264 /* LinphoneManagerTests.xctest */, + 8C90F57B1F94A621003B86C4 /* LinphoneManager.framework */, + 8C90F57D1F94A621003B86C4 /* LinphoneManagerTests.xctest */, ); name = Products; sourceTree = ""; @@ -4543,13 +4543,7 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; OTHER_LDFLAGS = "-ObjC"; @@ -4646,13 +4640,7 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; OTHER_LDFLAGS = "-ObjC"; @@ -4749,13 +4737,7 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; OTHER_LDFLAGS = "-ObjC"; @@ -4852,13 +4834,7 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; OTHER_LDFLAGS = "-ObjC"; From c9abca2710537e942583c9e55ee2c81566d9ad37 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Mon, 16 Oct 2017 11:03:53 +0200 Subject: [PATCH 08/42] fix warnings --- TestsUI/LinphoneTestCase.m | 3 +-- linphone.xcodeproj/project.pbxproj | 24 ++++-------------------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index ac2bb896e..a016034c2 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -127,8 +127,7 @@ linphone_address_set_header(testAddr, "X-Create-Account", "yes"); linphone_address_set_transport(testAddr, LinphoneTransportTcp); linphone_address_set_port(testAddr, 0); - - LinphoneProxyConfig *testProxy = linphone_core_create_proxy_config(LC); + LinphoneProxyConfig *testProxy = linphone_core_create_proxy_config(lc); linphone_proxy_config_set_identity_address(testProxy, testAddr); linphone_proxy_config_set_server_addr(testProxy, [self accountProxyRoute].UTF8String); linphone_proxy_config_set_route(testProxy, [self accountProxyRoute].UTF8String); diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 9a4701fa0..e7e66b662 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -5146,11 +5146,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5201,11 +5197,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -5256,11 +5248,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -5311,11 +5299,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; From 24733a06155d5a9a202cb6dca1b6a423fafcc6a5 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Wed, 8 Nov 2017 17:22:23 +0100 Subject: [PATCH 09/42] [CNContact] CNContact first implementation --- Classes/AssistantLinkView.m | 8 +- Classes/AssistantView.m | 27 +- Classes/Contact.h | 13 +- Classes/Contact.m | 976 +++++++++++++--------------- Classes/ContactDetailsTableView.m | 151 +++-- Classes/ContactDetailsView.m | 253 +++---- Classes/ContactsListTableView.m | 328 ++++++---- Classes/LinphoneAppDelegate.m | 87 +-- Classes/LinphoneCoreSettingsStore.m | 2 +- Classes/LinphoneManager.m | 6 +- Classes/Utils/FastAddressBook.h | 11 +- Classes/Utils/FastAddressBook.m | 392 ++++++----- TestsUI/LinphoneTestCase.m | 11 +- linphone.xcodeproj/project.pbxproj | 38 +- 14 files changed, 1184 insertions(+), 1119 deletions(-) diff --git a/Classes/AssistantLinkView.m b/Classes/AssistantLinkView.m index e268a8281..1b0bad163 100644 --- a/Classes/AssistantLinkView.m +++ b/Classes/AssistantLinkView.m @@ -199,10 +199,10 @@ void assistant_activate_phone_number_link(LinphoneAccountCreator *creator, Linph } [PhoneMainView.instance popToView:DialerView.compositeViewDescription]; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneAddressBookUpdate object:NULL]; - [LinphoneManager.instance.fastAddressBook reload]; - } else { - [thiz showErrorPopup:resp]; - } + [LinphoneManager.instance.fastAddressBook reloadAllContacts]; + } else { + [thiz showErrorPopup:resp]; + } } #pragma mark - other diff --git a/Classes/AssistantView.m b/Classes/AssistantView.m index 7c625dca5..4ed9c7420 100644 --- a/Classes/AssistantView.m +++ b/Classes/AssistantView.m @@ -412,10 +412,10 @@ static UICompositeViewDescription *compositeDescription = nil; linphone_core_set_default_proxy_config(LC, new_config); // reload address book to prepend proxy config domain to contacts' phone number // todo: STOP doing that! - [[LinphoneManager.instance fastAddressBook] reload]; - } else { - [self displayAssistantConfigurationError]; - } + [[LinphoneManager.instance fastAddressBook] reloadAllContacts]; + } else { + [self displayAssistantConfigurationError]; + } } - (void)displayAssistantConfigurationError { @@ -1366,14 +1366,17 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun linphone_core_set_default_proxy_config(LC, config); // reload address book to prepend proxy config domain to contacts' phone number // todo: STOP doing that! - [[LinphoneManager.instance fastAddressBook] reload]; - [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; - } else { - [self displayAssistantConfigurationError]; - } - } else { - [self displayAssistantConfigurationError]; - } + [[LinphoneManager.instance fastAddressBook] + reloadAllContacts]; + [PhoneMainView.instance + changeCurrentView: + DialerView.compositeViewDescription]; + } else { + [self displayAssistantConfigurationError]; + } + } else { + [self displayAssistantConfigurationError]; + } }); } diff --git a/Classes/Contact.h b/Classes/Contact.h index bd7cdbfad..292260607 100644 --- a/Classes/Contact.h +++ b/Classes/Contact.h @@ -6,28 +6,31 @@ // // -#import #import - +#import +#import #include @interface Contact : NSObject -@property(nonatomic, readonly) ABRecordRef person; +//@property(nonatomic, readonly) ABRecordRef person; +@property(nonatomic, readonly) CNContact *person; @property(nonatomic, readonly) LinphoneFriend *friend; +@property(nonatomic, retain) NSString *identifier; @property(nonatomic, retain) NSString *firstName; @property(nonatomic, retain) NSString *lastName; +@property(nonatomic, retain) NSString *displayName; @property(nonatomic, strong) NSMutableArray *sipAddresses; @property(nonatomic, strong) NSMutableArray *emails; -@property(nonatomic, strong) NSMutableArray *phoneNumbers; +@property(nonatomic, strong) NSMutableArray *phones; @property BOOL added; - (void)setAvatar:(UIImage *)avatar; - (UIImage *)avatar; - (NSString *)displayName; -- (instancetype)initWithPerson:(ABRecordRef)person; +- (instancetype)initWithCNContact:(CNContact *)contact; - (instancetype)initWithFriend:(LinphoneFriend *) friend; - (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index; diff --git a/Classes/Contact.m b/Classes/Contact.m index 74435fa9c..e143728fa 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -11,81 +11,96 @@ @implementation Contact -- (instancetype)initWithPerson:(ABRecordRef)aperson { - return [self initWithPerson:aperson andFriend:NULL]; +- (instancetype)initWithCNContact:(CNContact *)acncontact { + return [self initWithPerson:acncontact andFriend:NULL]; } - (instancetype)initWithFriend:(LinphoneFriend *)afriend { return [self initWithPerson:NULL andFriend:afriend]; } -- (instancetype)initWithPerson:(ABRecordRef)aperson andFriend:(LinphoneFriend *)afriend { - self = [super init]; - _person = aperson; - _friend = afriend ? linphone_friend_ref(afriend) : NULL; - _added = FALSE; - if (_person) { - [self loadProperties]; +- (instancetype)initWithPerson:(CNContact *)acncontact + andFriend:(LinphoneFriend *)afriend { + self = [super init]; + _person = acncontact; + _friend = afriend ? linphone_friend_ref(afriend) : NULL; + _added = FALSE; + _phones = [[NSMutableArray alloc] init]; + _sipAddresses = [[NSMutableArray alloc] init]; + _emails = [[NSMutableArray alloc] init]; + if (_person) { + _identifier = _person.identifier; + _firstName = _person.givenName; + _lastName = _person.familyName; + _displayName = [NSString stringWithFormat:@"%@ %@", _firstName, _lastName]; + for (CNLabeledValue *phoneNumber in _person.phoneNumbers) { + [_phones addObject:phoneNumber.value.stringValue]; + } + if ([_person respondsToSelector:NSSelectorFromString( + CNInstantMessageAddressUsernameKey)] || + [_person respondsToSelector:NSSelectorFromString( + CNContactInstantMessageAddressesKey)]) { + if (_person.instantMessageAddresses != NULL) { + for (CNLabeledValue *sipAddr in _person + .instantMessageAddresses) { + [_sipAddresses addObject:sipAddr.value.username]; + } + } + } + for (CNLabeledValue *email in _person.emailAddresses) { + [_emails addObject:email.value]; + } + const char *key = + [NSString stringWithFormat:@"ab%@", acncontact.identifier].UTF8String; + // try to find friend associated with that person + _friend = linphone_friend_list_find_friend_by_ref_key( + linphone_core_get_default_friend_list(LC), key); + if (!_friend) { + _friend = linphone_friend_ref(linphone_core_create_friend(LC)); + linphone_friend_set_ref_key(_friend, key); + linphone_friend_set_name( + _friend, + [NSString + stringWithFormat:@"%@%@", _firstName ? _firstName : @"", + _lastName + ? [_firstName ? @" " : @"" + stringByAppendingString:_lastName] + : @""] + .UTF8String); + for (NSString *sipAddr in _sipAddresses) { + LinphoneAddress *addr = + linphone_core_interpret_url(LC, sipAddr.UTF8String); + if (addr) { + linphone_address_set_display_name(addr, + [self displayName].UTF8String); + linphone_friend_add_address(_friend, addr); + linphone_address_destroy(addr); + } + } + for (NSString *phone in _phones) { + linphone_friend_add_phone_number(_friend, phone.UTF8String); + } + if (_friend) { + linphone_friend_enable_subscribes(_friend, FALSE); + linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny); + linphone_core_add_friend(LC, _friend); + } + } + linphone_friend_ref(_friend); + } else if (_friend) { + [self loadFriend]; + } else { + LOGE(@"Contact cannot be initialized"); + return nil; + } - const char* key = [NSString stringWithFormat:@"ab%d", ABRecordGetRecordID(aperson)].UTF8String; - // try to find friend associated with that person - _friend = linphone_friend_list_find_friend_by_ref_key(linphone_core_get_default_friend_list(LC), key); - if (!_friend) { - _friend = linphone_friend_ref(linphone_core_create_friend(LC)); - linphone_friend_set_ref_key(_friend, key); - linphone_friend_set_name( - _friend, - [NSString - stringWithFormat:@"%@%@", _firstName ? _firstName : @"", - _lastName ? [_firstName ? @" " : @"" stringByAppendingString:_lastName] : @""] - .UTF8String); - for (NSString* sipAddr in _sipAddresses) { - LinphoneAddress* addr = linphone_core_interpret_url(LC, sipAddr.UTF8String); - if (addr) { - linphone_address_set_display_name(addr, [self displayName].UTF8String); - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - } - } - for (NSString* phone in _phoneNumbers) { -#if 0 - char* normalized_phone = linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); - if (normalized_phone) { - LinphoneAddress* addr = linphone_core_interpret_url(LC, normalized_phone); - if (addr) { - linphone_address_set_display_name(addr, [self displayName].UTF8String); - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - } - ms_free(normalized_phone); - } -#else - linphone_friend_add_phone_number(_friend, phone.UTF8String); -#endif - } - if (_friend) { - linphone_friend_enable_subscribes(_friend, FALSE); - linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny); - linphone_core_add_friend(LC, _friend); - } - } - linphone_friend_ref(_friend); - } else if (_friend) { - [self loadFriend]; - } else { - LOGE(@"Contact cannot be initialized"); - return nil; - } - - LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", self.firstName ?: @"", self.lastName ?: @"", - self.phoneNumbers.count, self.sipAddresses.count, self.emails.count); - return self; + LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", + self.firstName ?: @"", self.lastName ?: @"", self.phones.count, + self.sipAddresses.count, self.emails.count); + return self; } - (void)dealloc { - if (_person != nil && ABRecordGetRecordID(_person) == kABRecordInvalidID) { - CFRelease(_person); - } if (_friend) { linphone_friend_unref(_friend); } @@ -95,11 +110,15 @@ #pragma mark - Getters - (UIImage *)avatar { - if (_person && ABPersonHasImageData(_person)) { - NSData *imgData = CFBridgingRelease(ABPersonCopyImageDataWithFormat(_person, kABPersonImageFormatThumbnail)); - return [UIImage imageWithData:imgData]; - } - return nil; + if (_person) { + @try { + return [UIImage imageWithData:_person.imageData]; + } @catch (NSException *e) { + LOGE(@"CNContact imageData CNPropertyNotFetchedException : %@", e); + return nil; + } + } + return nil; } - (NSString *)displayName { @@ -111,506 +130,401 @@ } if (_person != nil) { - NSString *lFirstName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty)); - NSString *lLocalizedFirstName = [FastAddressBook localizedLabel:lFirstName]; - NSString *compositeName = CFBridgingRelease(ABRecordCopyCompositeName(_person)); + NSString *lFirstName = _person.givenName; + NSString *lLocalizedFirstName = + [FastAddressBook localizedLabel:lFirstName]; - NSString *lLastName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonLastNameProperty)); - NSString *lLocalizedLastName = [FastAddressBook localizedLabel:lLastName]; + NSString *compositeName = _person.nickname; - NSString *lOrganization = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonOrganizationProperty)); - NSString *lLocalizedOrganization = [FastAddressBook localizedLabel:lOrganization]; + NSString *lLastName = _person.familyName; + NSString *lLocalizedLastName = + [FastAddressBook localizedLabel:lLastName]; - if (compositeName) { - return compositeName; - } else if (lLocalizedFirstName || lLocalizedLastName) { - return [NSString stringWithFormat:@"%@ %@", lLocalizedFirstName, lLocalizedLastName]; - } else { - return (NSString *)lLocalizedOrganization; - } - } + NSString *lOrganization = _person.organizationName; + NSString *lLocalizedOrganization = + [FastAddressBook localizedLabel:lOrganization]; - if (_lastName || _firstName) { - NSMutableString *str; - if (_firstName) - [str appendString:_firstName]; - if (_firstName && _lastName) - [str appendString:@" "]; - if (_lastName) - [str appendString:_lastName]; - } + if (compositeName) { + return compositeName; + } else if (lLocalizedFirstName || lLocalizedLastName) { + return [NSString stringWithFormat:@"%@ %@", lLocalizedFirstName, + lLocalizedLastName]; + } else { + return (NSString *)lLocalizedOrganization; + } + } - return NSLocalizedString(@"Unknown", nil); + if (_lastName || _firstName) { + NSMutableString *str; + if (_firstName) + [str appendString:_firstName]; + if (_firstName && _lastName) + [str appendString:@" "]; + if (_lastName) + [str appendString:_lastName]; + } + + return NSLocalizedString(@"Unknown", nil); } #pragma mark - Setters - (void)setAvatar:(UIImage *)avatar { - if (_person) { - CFErrorRef error = NULL; - if (!ABPersonRemoveImageData(_person, &error)) { - LOGW(@"Can't remove entry: %@", [(__bridge NSError *)error localizedDescription]); - } - NSData *dataRef = UIImageJPEGRepresentation(avatar, 0.9f); - CFDataRef cfdata = CFDataCreate(NULL, [dataRef bytes], [dataRef length]); - - if (!ABPersonSetImageData(_person, cfdata, &error)) { - LOGW(@"Can't add entry: %@", [(__bridge NSError *)error localizedDescription]); - } - - CFRelease(cfdata); - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } + BOOL ret = FALSE; + if (_person) { + NSData *imageAvatar = UIImageJPEGRepresentation(avatar, 0.9f); + [_person setValue:imageAvatar forKey:CNContactImageDataKey]; + ret = TRUE; + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); + } } - (void)setFirstName:(NSString *)firstName { BOOL ret = FALSE; - if (_person) { - ret = ([self replaceInProperty:kABPersonFirstNameProperty value:(__bridge CFTypeRef)(firstName)]); - } else { - ret = (linphone_friend_set_name(_friend, firstName.UTF8String) == 0); - } - - if (ret) { - _firstName = firstName; - } + if (![firstName isEqualToString:_firstName]) { + if (_friend) + ret = linphone_friend_set_name( + _friend, [NSString stringWithFormat:@"%@ %@", firstName, + _person.familyName] + .UTF8String); + if (_person) { + [_person setValue:firstName forKey:CNContactGivenNameKey]; + [_person setValue:[NSString stringWithFormat:@"%@ %@", firstName, + _person.familyName] + forKey:CNContactNicknameKey]; + ret = TRUE; + } + if (ret) { + _firstName = firstName; + _displayName = [NSString + stringWithFormat:@"%@ %@", firstName, _person.familyName]; + } + } } - (void)setLastName:(NSString *)lastName { BOOL ret = FALSE; - if (_person) { - ret = ([self replaceInProperty:kABPersonLastNameProperty value:(__bridge CFTypeRef)(lastName)]); - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - - if (ret) { - _lastName = lastName; - } + if (_friend) + ret = linphone_friend_set_name( + _friend, + [NSString stringWithFormat:@"%@ %@", _person.givenName, lastName] + .UTF8String); + if (_person) { + [_person setValue:lastName forKey:CNContactFamilyNameKey]; + [_person + setValue:[NSString stringWithFormat:@"%@ %@", _person.givenName, + lastName] + forKey:CNContactNicknameKey]; + ret = TRUE; + } + if (ret) { + _lastName = lastName; + _displayName = + [NSString stringWithFormat:@"%@ %@", _person.givenName, lastName]; + } } - (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index { BOOL ret = FALSE; NSString *normSip = NULL; - if (_person) { - normSip = [self setOrCreateSipContactEntry:index withValue:sip]; - NSDictionary *lDict = @{ - (NSString *)kABPersonInstantMessageUsernameKey : normSip ? normSip : sip, - (NSString *)kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField - }; + if (_person && ![sip isEqualToString:@" "]) { + if ((index + 1) > [_person.instantMessageAddresses count]) { + normSip = + [FastAddressBook normalizeSipURI:[sip substringFromIndex:1]]; + CNInstantMessageAddress *cNSipMsgAddr = [ + [CNInstantMessageAddress alloc] + initWithUsername:[normSip componentsSeparatedByString:@"@"][0] + service:[normSip componentsSeparatedByString:@"@"][1]]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:cNSipMsgAddr]; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress addObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + _sipAddresses[index] = [sip substringFromIndex:1]; + } else { + normSip = sip; + CNInstantMessageAddress *cNSipMsgAddr; + if ([normSip containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:[normSip componentsSeparatedByString:@"@"][0] + service:[normSip + componentsSeparatedByString:@"@"][1]]; + else + cNSipMsgAddr = + [[CNInstantMessageAddress alloc] initWithUsername:normSip + service:normSip]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:cNSipMsgAddr]; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress replaceObjectAtIndex:index withObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + } + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } - ret = [self replaceInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict) atIndex:index]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - - if (ret) { - _sipAddresses[index] = sip; - } - return ret; + if (ret) { + _sipAddresses[index] = sip; + } + return ret; } - (BOOL)setPhoneNumber:(NSString *)phone atIndex:(NSInteger)index { BOOL ret = FALSE; if (_person) { - ret = [self replaceInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone) atIndex:index]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - if (ret) { - _phoneNumbers[index] = phone; - } - return ret; + if ((index + 1) > [_person.phoneNumbers count]) { + CNLabeledValue *mobileNumber = [CNLabeledValue + labeledValueWithLabel:CNLabelPhoneNumberMobile + value:[CNPhoneNumber + phoneNumberWithStringValue:phone]]; + NSMutableArray *> *tmpPhoneNumbers = + [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers addObject:mobileNumber]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } else { + CNLabeledValue *mobileNumber = [CNLabeledValue + labeledValueWithLabel:CNLabelPhoneNumberMobile + value:[CNPhoneNumber + phoneNumberWithStringValue:phone]]; + NSMutableArray *> *tmpPhoneNumbers = + [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers replaceObjectAtIndex:index + withObject:mobileNumber]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + if (ret) + _phones[index] = phone; + return ret; } - (BOOL)setEmail:(NSString *)email atIndex:(NSInteger)index { BOOL ret = FALSE; if (_person) { - ret = [self replaceInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email) atIndex:index]; - } else { - } - if (ret) { - _emails[index] = email; - } - return ret; + if ((index + 1) > [_person.emailAddresses count]) { + CNLabeledValue *emailAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:email]; + NSMutableArray *> *tmpEmailAddress = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddress addObject:emailAddress]; + [_person setValue:tmpEmailAddress + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } else { + CNLabeledValue *emailAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:email]; + NSMutableArray *> *tmpEmailAddress = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddress replaceObjectAtIndex:index + withObject:emailAddress]; + [_person setValue:tmpEmailAddress + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + if (ret) + _emails[index] = email; + return ret; } - (BOOL)addSipAddress:(NSString *)sip { BOOL ret = FALSE; - if (_person) { - NSDictionary *lDict = @{ - (NSString *) kABPersonInstantMessageUsernameKey : sip, (NSString *) - kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField - }; - - ret = [self addInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict)]; - } else { - LinphoneAddress *addr = linphone_core_interpret_url(LC, sip.UTF8String) ?: linphone_address_new(sip.UTF8String); - if (addr) { - ret = TRUE; - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - // ensure that it was added by checking list size - ret = (bctbx_list_size(linphone_friend_get_addresses(_friend)) == _sipAddresses.count + 1); - } - } - if (ret) { - [_sipAddresses addObject:sip]; - } - return ret; + NSString *normSip = NULL; + if (sip != NULL && ![sip isEqualToString:@""]) { + if ([sip isEqualToString:@" "]) + ret = TRUE; + else { + if (_person) { + normSip = sip; + CNInstantMessageAddress *cNSipMsgAddr; + if ([normSip containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:[normSip + componentsSeparatedByString:@"@"][0] + service:[normSip + componentsSeparatedByString:@"@"][1]]; + else + cNSipMsgAddr = + [[CNInstantMessageAddress alloc] initWithUsername:normSip + service:normSip]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL + value:cNSipMsgAddr]; + NSMutableArray *> * + tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress addObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + } else { + LinphoneAddress *addr = + linphone_core_interpret_url(LC, sip.UTF8String) + ?: linphone_address_new(sip.UTF8String); + if (addr) { + ret = TRUE; + linphone_friend_add_address(_friend, addr); + linphone_address_destroy(addr); + // ensure that it was added by checking list size + ret = + (bctbx_list_size(linphone_friend_get_addresses(_friend)) == + _sipAddresses.count + 1); + } + } + } + } + if (ret) { + [_sipAddresses addObject:sip]; + } + return ret; } - (BOOL)addPhoneNumber:(NSString *)phone { BOOL ret = FALSE; - if (_person) { - ret = [self addInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone)]; - } else { - char *cphone = ms_strdup(phone.UTF8String); - // linphone_proxy_config_normalize_phone_number(NULL, phone.UTF8String) ?: ms_strdup(phone.UTF8String); - if (cphone) { - linphone_friend_add_phone_number(_friend, cphone); - phone = [NSString stringWithUTF8String:cphone]; - ms_free(cphone); - // ensure that it was added by checking list size - ret = (bctbx_list_size(linphone_friend_get_phone_numbers(_friend)) == _phoneNumbers.count + 1); - } - } - if (ret) { - [_phoneNumbers addObject:phone]; - } - return ret; + if (phone != NULL && ![phone isEqualToString:@""]) { + if ([phone isEqualToString:@" "]) + ret = TRUE; + else { + if (_person) { + CNLabeledValue *mobileNumber = [CNLabeledValue + labeledValueWithLabel:CNLabelPhoneNumberMobile + value:[CNPhoneNumber + phoneNumberWithStringValue:phone]]; + NSMutableArray *> + *tmpPhoneNumbers = [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers addObject:mobileNumber]; + [_person setValue:tmpPhoneNumbers + forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } else { + char *cphone = ms_strdup(phone.UTF8String); + if (cphone) { + linphone_friend_add_phone_number(_friend, cphone); + phone = [NSString stringWithUTF8String:cphone]; + ms_free(cphone); + // ensure that it was added by checking list size + ret = (bctbx_list_size(linphone_friend_get_phone_numbers( + _friend)) == _phones.count + 1); + } + } + } + } + if (ret) { + [_phones addObject:phone]; + } + return ret; } - (BOOL)addEmail:(NSString *)email { BOOL ret = FALSE; - if (_person) { - ret = [self addInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email)]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - if (ret) { - [_emails addObject:email]; - } - return ret; + if (email != NULL && ![email isEqualToString:@""]) { + if ([email isEqualToString:@" "]) + ret = TRUE; + else { + if (_person) { + CNLabeledValue *emailAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:email]; + NSMutableArray *> *tmpEmailAddress = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddress addObject:emailAddress]; + [_person setValue:tmpEmailAddress + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + } + } + if (ret) { + [_emails addObject:email]; + } + return ret; } - (BOOL)removeSipAddressAtIndex:(NSInteger)index { BOOL ret = FALSE; if (_person) { - ret = [self removeInProperty:kABPersonInstantMessageProperty atIndex:index]; - } else { - LinphoneAddress *addr = linphone_core_interpret_url(LC, ((NSString *)_sipAddresses[index]).UTF8String); - if (addr) { - linphone_friend_remove_address(_friend, addr); - linphone_address_destroy(addr); - // ensure that it was destroyed by checking list size - ret = (bctbx_list_size(linphone_friend_get_addresses(_friend)) + 1 == _sipAddresses.count); - } - } - if (ret) { - [_sipAddresses removeObjectAtIndex:index]; - } - return ret; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress removeObjectAtIndex:index]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + } else { + LinphoneAddress *addr = linphone_core_interpret_url( + LC, ((NSString *)_sipAddresses[index]).UTF8String); + if (addr) { + linphone_friend_remove_address(_friend, addr); + linphone_address_destroy(addr); + // ensure that it was destroyed by checking list size + ret = + (bctbx_list_size(linphone_friend_get_addresses(_friend)) + 1 == + _sipAddresses.count); + } + } + if (ret) { + [_sipAddresses removeObjectAtIndex:index]; + } + return ret; } - (BOOL)removePhoneNumberAtIndex:(NSInteger)index { BOOL ret = FALSE; - if (_person) { - ret = [self removeInProperty:kABPersonPhoneProperty atIndex:index]; - } else { - const char *phone = ((NSString *)_phoneNumbers[index]).UTF8String; - linphone_friend_remove_phone_number(_friend, phone); - // ensure that it was destroyed by checking list size - ret = (bctbx_list_size(linphone_friend_get_phone_numbers(_friend)) + 1 == _phoneNumbers.count); - } - if (ret) { - [_phoneNumbers removeObjectAtIndex:index]; - } - return ret; + if (_person && _person.phoneNumbers.count > 0) { + NSMutableArray *> *tmpPhoneNumbers = + [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers removeObjectAtIndex:index]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } else { + const char *phone = ((NSString *)_phones[index]).UTF8String; + linphone_friend_remove_phone_number(_friend, phone); + // ensure that it was destroyed by checking list size + // ret = (bctbx_list_size(linphone_friend_get_phone_numbers(_friend)) + // + 1 == _phoneNumbers.count); + ret = TRUE; + } + if (ret) { + [_phones removeObjectAtIndex:index]; + } + return ret; } - (BOOL)removeEmailAtIndex:(NSInteger)index { BOOL ret = FALSE; if (_person) { - ret = [self removeInProperty:kABPersonEmailProperty atIndex:index]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - if (ret) { - [_emails removeObjectAtIndex:index]; - } - return ret; + NSMutableArray *> *tmpEmailAddresses = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddresses removeObjectAtIndex:index]; + [_person setValue:tmpEmailAddresses + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + if (ret) { + [_emails removeObjectAtIndex:index]; + } + return ret; } -#pragma mark - ABPerson utils -- (NSString *)setOrCreateSipContactEntry:(NSInteger)index withValue:(NSString *)value { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - ABMutableMultiValueRef lMap; - NSString *ret = NULL; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - CFErrorRef error = NULL; - - NSDictionary *lDict = @{ - (NSString *)kABPersonInstantMessageUsernameKey : value, - (NSString *)kABPersonInstantMessageServiceKey : [LinphoneManager instance].contactSipField - }; - - if (![self replaceInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict) atIndex:index]) { - LOGI(@"Can't set contact with value [%@] cause [%@]", value, [(__bridge NSError *)error localizedDescription]); - CFRelease(lMap); - } else { - CFRelease(lMap); - - /*check if message type is kept or not*/ - lcMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - lDict = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index)); - - if ([lDict objectForKey:(__bridge NSString *)kABPersonInstantMessageServiceKey] == nil) { - /*too bad probably a gtalk number, storing uri*/ - ret = [FastAddressBook normalizeSipURI:value]; - } else if (!_added) { - _added = TRUE; - [LinphoneManager.instance.fastAddressBook saveContact:self]; - } - CFRelease(lMap); - } - return ret ? ret : value; -} - -- (void)loadProperties { - // First and Last name - { - _firstName = (NSString *)CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty)); - _lastName = (NSString *)CFBridgingRelease(ABRecordCopyValue(_person, kABPersonLastNameProperty)); - } - - // Phone numbers - { - _phoneNumbers = [[NSMutableArray alloc] init]; - ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonPhoneProperty); - if (map) { - for (int i = 0; i < ABMultiValueGetCount(map); ++i) { - ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(map, i); - NSInteger index = ABMultiValueGetIndexForIdentifier(map, identifier); - if (index != -1) { - NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(map, index)); - // char *normalizedPhone = linphone_proxy_config_normalize_phone_number( - // linphone_core_get_default_proxy_config(LC), valueRef.UTF8String); - // if (normalizedPhone) { - // valueRef = [NSString stringWithUTF8String:normalizedPhone]; - // ms_free(normalizedPhone); - //} - - [_phoneNumbers addObject:valueRef]; - } - } - CFRelease(map); - } - } - - // SIP (IM) - /*{ - _sipAddresses = [[NSMutableArray alloc] init]; - ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - if (map) { - for (int i = 0; i < ABMultiValueGetCount(map); ++i) { - CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(map, i); - if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { - if (CFStringCompare((CFStringRef)LinphoneManager.instance.contactSipField, - CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), - kCFCompareCaseInsensitive) == 0) { - NSString *value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey)); - CFRelease(lDict); - if (value != NULL) { - [_sipAddresses addObject:value]; - } - } - } - } - CFRelease(map); - } - }*/ - - // SIP (IM) - { - _sipAddresses = [[NSMutableArray alloc] init]; - ABMultiValueRef lMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - if (lMap) { - for (int i = 0; i < ABMultiValueGetCount(lMap); ++i) { - CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i); - BOOL add = false; - if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { - if (CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, - CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), - kCFCompareCaseInsensitive) == 0) { - add = true; - } - } else { - // check domain - LinphoneAddress *address = linphone_address_new( - [(NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey) UTF8String]); - if (address) { - if ([[ContactSelection getSipFilter] compare:@"*" options:NSCaseInsensitiveSearch] == - NSOrderedSame) { - add = true; - } else { - NSString *domain = [NSString stringWithCString:linphone_address_get_domain(address) - encoding:[NSString defaultCStringEncoding]]; - add = [domain compare:[ContactSelection getSipFilter] options:NSCaseInsensitiveSearch] == - NSOrderedSame; - } - linphone_address_destroy(address); - } else { - add = false; - } - } - if (add) { - NSString *value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey)); - if (value != NULL) { - [_sipAddresses addObject:value]; - } - } - CFRelease(lDict); - } - CFRelease(lMap); - } - } - - // SIP - /*{ - _sipAddresses = [[NSMutableArray alloc] init]; - ABMultiValueRef lMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - if (lMap) { - for (int i = 0; i < ABMultiValueGetCount(lMap); ++i) { - CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i); - BOOL add = false; - if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { - if (CFStringCompare((CFStringRef)LinphoneManager.instance.contactSipField, - CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), - kCFCompareCaseInsensitive) == 0) { - add = true; - } - } else { - add = true; - } - if (add) { - NSString *lValue = - (__bridge NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey); - if(lValue) { - NSString *lNormalizedKey = [FastAddressBook normalizeSipURI:lValue]; - if (lNormalizedKey != NULL) { - [_sipAddresses addObject:lNormalizedKey]; - } else { - [_sipAddresses addObject:lValue]; - } - } - } - CFRelease(lDict); - } - CFRelease(lMap); - } - }*/ - - // Email - { - _emails = [[NSMutableArray alloc] init]; - ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonEmailProperty); - if (map) { - for (int i = 0; i < ABMultiValueGetCount(map); ++i) { - ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(map, i); - NSInteger index = ABMultiValueGetIndexForIdentifier(map, identifier); - if (index != -1) { - NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(map, index)); - if (valueRef != NULL) { - [_emails addObject:valueRef]; - } - } - } - CFRelease(map); - } - } -} - -- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value { - CFErrorRef error = NULL; - if (!ABRecordSetValue(_person, property, value, &error)) { - LOGE(@"Error when saving property %d in contact %p: Fail(%@)", property, _person, error); - return NO; - } - return YES; -} - -- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value atIndex:(NSInteger)index { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, property); - ABMutableMultiValueRef lMap; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - - BOOL ret = ABMultiValueReplaceValueAtIndex(lMap, value, index); - if (ret) { - ret = [self replaceInProperty:property value:lMap]; - } else { - LOGW(@"Could not replace %@ at index %d from property %d", value, index, property); - } - - CFRelease(lMap); - return ret; -} - -- (BOOL)addInProperty:(ABPropertyID)property value:(CFTypeRef)value { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, property); - ABMutableMultiValueRef lMap; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - - // will display this field with our application name - CFStringRef label = (__bridge CFStringRef)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - BOOL ret = ABMultiValueAddValueAndLabel(lMap, value, label, nil); - if (ret) { - ret = [self replaceInProperty:property value:lMap]; - } else { - LOGW(@"Could not add %@ to property %d", value, property); - } - CFRelease(lMap); - return ret; -} - -- (BOOL)removeInProperty:(ABPropertyID)property atIndex:(NSInteger)index { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, property); - ABMutableMultiValueRef lMap; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - - BOOL ret = ABMultiValueRemoveValueAndLabelAtIndex(lMap, index); - if (ret) { - ret = [self replaceInProperty:property value:lMap]; - } else { - LOGW(@"Could not remove at index %d from property %d", index, property); - } - - CFRelease(lMap); - return ret; -} #pragma mark - LinphoneFriend utils @@ -623,32 +537,32 @@ // Phone numbers { - _phoneNumbers = [[NSMutableArray alloc] init]; - MSList *numbers = linphone_friend_get_phone_numbers(_friend); - while (numbers) { - NSString *phone = [NSString stringWithUTF8String:numbers->data]; - [_phoneNumbers addObject:phone]; - numbers = numbers->next; - } - } + _phones = [[NSMutableArray alloc] init]; + MSList *numbers = linphone_friend_get_phone_numbers(_friend); + while (numbers) { + NSString *phone = [NSString stringWithUTF8String:numbers->data]; + [_phones addObject:phone]; + numbers = numbers->next; + } + } - // SIP (IM) - { - _sipAddresses = [[NSMutableArray alloc] init]; - const MSList *sips = linphone_friend_get_addresses(_friend); - while (sips) { - LinphoneAddress *addr = sips->data; - char *uri = linphone_address_as_string_uri_only(addr); - NSString *sipaddr = [NSString stringWithUTF8String:uri]; - [_sipAddresses addObject:sipaddr]; - ms_free(uri); + // SIP (IM) + { + _sipAddresses = [[NSMutableArray alloc] init]; + const MSList *sips = linphone_friend_get_addresses(_friend); + while (sips) { + LinphoneAddress *addr = sips->data; + char *uri = linphone_address_as_string_uri_only(addr); + NSString *sipaddr = [NSString stringWithUTF8String:uri]; + [_sipAddresses addObject:sipaddr]; + ms_free(uri); - sips = sips->next; - } - } + sips = sips->next; + } + } - // Email - no support for LinphoneFriend - { _emails = [[NSMutableArray alloc] init]; } + // Email - no support for LinphoneFriend + { _emails = [[NSMutableArray alloc] init]; } } @end diff --git a/Classes/ContactDetailsTableView.m b/Classes/ContactDetailsTableView.m index f22220acc..bf44219bd 100644 --- a/Classes/ContactDetailsTableView.m +++ b/Classes/ContactDetailsTableView.m @@ -29,15 +29,17 @@ - (NSMutableArray *)getSectionData:(NSInteger)section { if (section == ContactSections_Number) { - return _contact.phoneNumbers; - } else if (section == ContactSections_Sip) { - return _contact.sipAddresses; - } else if (section == ContactSections_Email) { - if ([LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) { - return _contact.emails; - } - } - return nil; + return _contact.phones; + } else if (section == ContactSections_Sip) { + return _contact.sipAddresses; + } else if (section == ContactSections_Email) { + if ([LinphoneManager.instance + lpConfigBoolForKey:@"show_contacts_emails_preference"] == + true) { + return _contact.emails; + } + } + return nil; } - (void)removeEmptyEntry:(UITableView *)tableview section:(NSInteger)section animated:(BOOL)animated { @@ -75,25 +77,30 @@ if (section == ContactSections_Number) { added = [_contact addPhoneNumber:value]; } else if (section == ContactSections_Sip) { - added = [_contact addSipAddress:value]; - } else if (section == ContactSections_Email) { - added = [_contact addEmail:value]; - } - - if (added) { - NSUInteger count = [self getSectionData:section].count; - [tableview insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:count - 1 inSection:section] ] - withRowAnimation:animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone]; - } else { - LOGW(@"Cannot add entry '%@' in section %d, skipping", value, section); - } + if ([_contact.sipAddresses count] == + [_contact.person.instantMessageAddresses count]) + added = [_contact addSipAddress:value]; + } else if (section == ContactSections_Email) { + added = [_contact addEmail:value]; + } + if (added) { + NSUInteger count = [self getSectionData:section].count; + [tableview + insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:count - 1 + inSection:section] ] + withRowAnimation:animated ? UITableViewRowAnimationFade + : UITableViewRowAnimationNone]; + } else { + LOGW(@"Cannot add entry '%@' in section %d, skipping", value, + section); + } } - (void)setContact:(Contact *)acontact { - if (acontact == _contact) - return; - _contact = acontact; - [self loadData]; + // if (acontact == _contact) + // return; + _contact = acontact; + [self loadData]; } - (void)addPhoneField:(NSString *)number { @@ -119,8 +126,9 @@ - (BOOL)isValid { BOOL hasName = (_contact.firstName.length + _contact.lastName.length > 0); - BOOL hasAddr = (_contact.phoneNumbers.count + _contact.sipAddresses.count) > 0; - return hasName && hasAddr; + BOOL hasAddr = + (_contact.phones.count + _contact.sipAddresses.count) > 0; + return hasName && hasAddr; } #pragma mark - UITableViewDataSource Functions @@ -140,12 +148,13 @@ } else if (section == ContactSections_Sip) { return _contact.sipAddresses.count; } else if (section == ContactSections_Number) { - return _contact.phoneNumbers.count; - } else if (section == ContactSections_Email) { - BOOL showEmails = [LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"]; - return showEmails ? _contact.emails.count : 0; - } - return 0; + return _contact.phones.count; + } else if (section == ContactSections_Email) { + BOOL showEmails = [LinphoneManager.instance + lpConfigBoolForKey:@"show_contacts_emails_preference"]; + return showEmails ? _contact.emails.count : 0; + } + return 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -169,26 +178,28 @@ value = _contact.lastName; [cell hideDeleteButton:YES]; } else if ([indexPath section] == ContactSections_Number) { - value = _contact.phoneNumbers[indexPath.row]; - [cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad]; - } else if ([indexPath section] == ContactSections_Sip) { - value = _contact.sipAddresses[indexPath.row]; - LinphoneAddress *addr = NULL; - if ([LinphoneManager.instance lpConfigBoolForKey:@"contact_display_username_only"] && - (addr = linphone_core_interpret_url(LC, [value UTF8String]))) { - value = [NSString stringWithCString:linphone_address_get_username(addr) - encoding:[NSString defaultCStringEncoding]]; - linphone_address_destroy(addr); - } - [cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable]; - } else if ([indexPath section] == ContactSections_Email) { - value = _contact.emails[indexPath.row]; - [cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress]; - } + value = _contact.phones[indexPath.row]; + [cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad]; + } else if ([indexPath section] == ContactSections_Sip) { + value = _contact.sipAddresses[indexPath.row]; + LinphoneAddress *addr = NULL; + if ([LinphoneManager.instance + lpConfigBoolForKey:@"contact_display_username_only"] && + (addr = linphone_core_interpret_url(LC, [value UTF8String]))) { + value = + [NSString stringWithCString:linphone_address_get_username(addr) + encoding:[NSString defaultCStringEncoding]]; + linphone_address_destroy(addr); + } + [cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable]; + } else if ([indexPath section] == ContactSections_Email) { + value = _contact.emails[indexPath.row]; + [cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress]; + } - [cell setAddress:value]; + [cell setAddress:value]; - return cell; + return cell; } - (void)tableView:(UITableView *)tableView @@ -197,13 +208,16 @@ [LinphoneUtils findAndResignFirstResponder:[self tableView]]; if (editingStyle == UITableViewCellEditingStyleInsert) { [tableView beginUpdates]; - [self addEntry:tableView section:[indexPath section] animated:TRUE value:@""]; - [tableView endUpdates]; - } else if (editingStyle == UITableViewCellEditingStyleDelete) { - [tableView beginUpdates]; - [self removeEntry:tableView indexPath:indexPath animated:TRUE]; - [tableView endUpdates]; - } + [self addEntry:tableView + section:[indexPath section] + animated:TRUE + value:@" "]; + [tableView endUpdates]; + } else if (editingStyle == UITableViewCellEditingStyleDelete) { + [tableView beginUpdates]; + [self removeEntry:tableView indexPath:indexPath animated:TRUE]; + [tableView endUpdates]; + } } #pragma mark - UITableViewDelegate Functions @@ -371,19 +385,22 @@ break; case ContactSections_Number: [_contact setPhoneNumber:value atIndex:path.row]; - value = _contact.phoneNumbers[path.row]; // in case of reformatting - break; - case ContactSections_MAX: - case ContactSections_None: - break; - } - cell.editTextfield.text = value; - _editButton.enabled = [self isValid]; - } + value = + _contact.phones[path.row]; // in case of + // reformatting + break; + case ContactSections_MAX: + case ContactSections_None: + break; + } + cell.editTextfield.text = value; + _editButton.enabled = [self isValid]; + } } - (void)textFieldDidEndEditing:(UITextField *)textField { [self textFieldUpdated:textField]; + // TODO reload current contact } - (BOOL)textField:(UITextField *)textField diff --git a/Classes/ContactDetailsView.m b/Classes/ContactDetailsView.m index 0fb0649e5..16bccb61d 100644 --- a/Classes/ContactDetailsView.m +++ b/Classes/ContactDetailsView.m @@ -29,12 +29,18 @@ self = [super initWithNibName:NSStringFromClass(self.class) bundle:[NSBundle mainBundle]]; if (self != nil) { inhibUpdate = FALSE; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; - } - return self; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:CNContactStoreDidChangeNotification + object:nil]; + } + return self; } - (void)dealloc { @@ -44,11 +50,12 @@ #pragma mark - - (void)onAddressBookUpdate:(NSNotification *)k { - if (!inhibUpdate && ![_tableController isEditing] && - (PhoneMainView.instance.currentView == self.compositeViewDescription) && - (_nameLabel.text == PhoneMainView.instance.currentName)) { - [self resetData]; - } + + if (!inhibUpdate && ![_tableController isEditing] && + (PhoneMainView.instance.currentView == self.compositeViewDescription) && + (_nameLabel.text == PhoneMainView.instance.currentName)) { + [self resetData]; + } } - (void)resetData { @@ -67,9 +74,9 @@ - (void)removeContact { inhibUpdate = TRUE; - [[LinphoneManager.instance fastAddressBook] removeContact:_contact]; - inhibUpdate = FALSE; - [PhoneMainView.instance popCurrentView]; + [[LinphoneManager.instance fastAddressBook] deleteContact:_contact]; + inhibUpdate = FALSE; + [PhoneMainView.instance popCurrentView]; } - (void)saveData { @@ -77,9 +84,9 @@ [PhoneMainView.instance popCurrentView]; return; } - - // Add contact to book - [LinphoneManager.instance.fastAddressBook saveContact:_contact]; + PhoneMainView.instance.currentName = _contact.displayName; + _nameLabel.text = PhoneMainView.instance.currentName; + [LinphoneManager.instance.fastAddressBook saveContact:_contact]; } - (void)selectContact:(Contact *)acontact andReload:(BOOL)reload { @@ -109,12 +116,11 @@ if (!acontact) { return; } - _tmpContact = [[Contact alloc] initWithPerson:ABPersonCreate()]; - _tmpContact.firstName = acontact.firstName.copy; - _tmpContact.lastName = acontact.lastName.copy; - _tmpContact.sipAddresses = acontact.sipAddresses.copy; - _tmpContact.emails = acontact.emails.copy; - _tmpContact.phoneNumbers = acontact.phoneNumbers.copy; + @synchronized(LinphoneManager.instance.fastAddressBook) { + _tmpContact = [[Contact alloc] + initWithCNContact:[LinphoneManager.instance.fastAddressBook + getCNContactFromContact:acontact]]; + } } - (void)addCurrentContactContactField:(NSString *)address { @@ -140,14 +146,19 @@ - (void)newContact { _isAdding = TRUE; - [self selectContact:[[Contact alloc] initWithPerson:ABPersonCreate()] andReload:YES]; + CNContact *contact = [[CNContact alloc] init]; + [self selectContact:[[Contact alloc] initWithCNContact:contact] + andReload:YES]; } - (void)newContact:(NSString *)address { - [self selectContact:[[Contact alloc] initWithPerson:ABPersonCreate()] andReload:NO]; - [self addCurrentContactContactField:address]; - // force to restart server subscription to add new contact into the list - [LinphoneManager.instance becomeActive]; + CNContact *contact = [[CNContact alloc] init]; + Contact *mContact = [[Contact alloc] initWithCNContact:contact]; + [mContact setSipAddress:address atIndex:0]; + [self selectContact:mContact andReload:NO]; + [self addCurrentContactContactField:address]; + // force to restart server subscription to add new contact into the list + [LinphoneManager.instance becomeActive]; } - (void)editContact:(Contact *)acontact { @@ -256,47 +267,45 @@ [_contact addSipAddress:_tmpContact.sipAddresses[nbSipAd]]; nbSipAd++; } - - while (_contact.phoneNumbers.count > 0) { - [_contact removePhoneNumberAtIndex:0]; - - } - NSInteger nbPhone = 0; - while (_tmpContact.phoneNumbers.count> nbPhone) { - [_contact addPhoneNumber:_tmpContact.phoneNumbers[nbPhone]]; - nbPhone++; - } - - while (_contact.emails.count > 0) { - [_contact removeEmailAtIndex:0]; - - } - NSInteger nbEmail = 0; - while (_tmpContact.emails.count> nbEmail) { - [_contact addEmail:_tmpContact.emails[nbEmail]]; - nbEmail++; - } - self.tmpContact = NULL; - [self saveData]; - } - BOOL rm = TRUE; - for (NSString *sip in _contact.sipAddresses) { - if (![sip isEqualToString:@""]) { - rm = FALSE; - break; - } - } - if (rm) { - for (NSString *phone in _contact.phoneNumbers) { - if (![phone isEqualToString:@""]) { - rm = FALSE; - break; - } - } - } - if (rm) { - [LinphoneManager.instance.fastAddressBook removeContact:_contact]; - } + + while (_contact.phones.count > 0) { + [_contact removePhoneNumberAtIndex:0]; + } + NSInteger nbPhone = 0; + while (_tmpContact.phones.count > nbPhone) { + [_contact addPhoneNumber:_tmpContact.phones[nbPhone]]; + nbPhone++; + } + + while (_contact.emails.count > 0) { + [_contact removeEmailAtIndex:0]; + } + NSInteger nbEmail = 0; + while (_tmpContact.emails.count > nbEmail) { + [_contact addEmail:_tmpContact.emails[nbEmail]]; + nbEmail++; + } + self.tmpContact = NULL; + [self saveData]; + } + BOOL rm = TRUE; + for (NSString *sip in _contact.sipAddresses) { + if (![sip isEqualToString:@""]) { + rm = FALSE; + break; + } + } + if (rm) { + for (NSString *phone in _contact.phones) { + if (![phone isEqualToString:@""]) { + rm = FALSE; + break; + } + } + } + if (rm) { + [LinphoneManager.instance.fastAddressBook deleteContact:_contact]; + } } #pragma mark - UICompositeViewDelegate Functions @@ -397,55 +406,63 @@ static UICompositeViewDescription *compositeDescription = nil; [_contact removeSipAddressAtIndex:0]; } NSInteger nbSipAd = 0; - while (_tmpContact.sipAddresses.count > nbSipAd) { - [_contact addSipAddress:_tmpContact.sipAddresses[nbSipAd]]; - nbSipAd++; - } - - while (_contact.phoneNumbers.count > 0) { - [_contact removePhoneNumberAtIndex:0]; - } - NSInteger nbPhone = 0; - while (_tmpContact.phoneNumbers.count> nbPhone) { - [_contact addPhoneNumber:_tmpContact.phoneNumbers[nbPhone]]; - nbPhone++; - } - - while (_contact.emails.count > 0) { - [_contact removeEmailAtIndex:0]; - } - NSInteger nbEmail = 0; - while (_tmpContact.emails.count> nbEmail) { - [_contact addEmail:_tmpContact.emails[nbEmail]]; - nbEmail++; - } - [self saveData]; - [self.tableController.tableView reloadData]; - } else { - [LinphoneManager.instance.fastAddressBook removeContact:_contact]; - } - - [self setEditing:FALSE]; - if (IPAD) { - _emptyLabel.hidden = !_isAdding; - _avatarImage.hidden = !_emptyLabel.hidden; - _deleteButton.hidden = !_emptyLabel.hidden; - _editButton.hidden = !_emptyLabel.hidden; - } else { - if (_isAdding) { - [PhoneMainView.instance popCurrentView]; - } else { - _avatarImage.hidden = FALSE; - _deleteButton.hidden = FALSE; - _editButton.hidden = FALSE; - } - } - - self.tmpContact = NULL; - if (_isAdding) { - [PhoneMainView.instance popToView:ContactsListView.compositeViewDescription]; - _isAdding = FALSE; - } + if (_tmpContact.sipAddresses) { + while (_tmpContact.sipAddresses.count > nbSipAd) { + [_contact addSipAddress:_tmpContact.sipAddresses[nbSipAd]]; + nbSipAd++; + } + } + while (_contact.phones.count > 0 && + _contact.phones[0] != NULL) { + [_contact removePhoneNumberAtIndex:0]; + } + NSInteger nbPhone = 0; + if (_tmpContact.phones != NULL) { + while (_tmpContact.phones.count > nbPhone) { + [_contact addPhoneNumber:_tmpContact.phones[nbPhone]]; + nbPhone++; + } + } + while (_contact.emails.count > 0) { + [_contact removeEmailAtIndex:0]; + } + NSInteger nbEmail = 0; + if (_tmpContact.emails != NULL) { + while (_tmpContact.emails.count > nbEmail) { + [_contact addEmail:_tmpContact.emails[nbEmail]]; + // [_contact + // addPhoneNumber:((CNLabeledValue*)_tmpContact.phoneNumbers[nbPhone]).value.stringValue]; + nbEmail++; + } + } + [self saveData]; + //[self.tableController.tableView reloadData]; + } else { + [LinphoneManager.instance.fastAddressBook deleteContact:_contact]; + } + + [self setEditing:FALSE]; + if (IPAD) { + _emptyLabel.hidden = !_isAdding; + _avatarImage.hidden = !_emptyLabel.hidden; + _deleteButton.hidden = !_emptyLabel.hidden; + _editButton.hidden = !_emptyLabel.hidden; + } else { + if (_isAdding) { + [PhoneMainView.instance popCurrentView]; + } else { + _avatarImage.hidden = FALSE; + _deleteButton.hidden = FALSE; + _editButton.hidden = FALSE; + } + } + + self.tmpContact = NULL; + if (_isAdding) { + [PhoneMainView.instance + popToView:ContactsListView.compositeViewDescription]; + _isAdding = FALSE; + } } - (IBAction)onBackClick:(id)event { diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index 21b045b35..29a713e50 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -29,10 +29,16 @@ - (void)initContactsTableViewController { addressBookMap = [[OrderedDictionary alloc] init]; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:CNContactStoreDidChangeNotification + object:nil]; } - (void)onAddressBookUpdate:(NSNotification *)k { @@ -121,6 +127,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { return nil; } +// TODO - check this - (void)loadData { _ongoing = TRUE; LOGI(@"Load contact list"); @@ -136,67 +143,88 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { // Reset Address book [addressBookMap removeAllObjects]; - for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; - BOOL add = true; + @synchronized( + LinphoneManager.instance.fastAddressBook.addressBookMap) { + Contact *contact = + [LinphoneManager.instance.fastAddressBook.addressBookMap + objectForKey:addr]; + BOOL add = true; + // Do not add the contact directly if we set some filter + if ([ContactSelection getSipFilter] || + [ContactSelection emailFilterEnabled]) { + add = false; + } + if ([FastAddressBook contactHasValidSipDomain:contact]) { + add = true; + } + if (contact.friend && + linphone_presence_model_get_basic_status( + linphone_friend_get_presence_model( + contact.friend)) == + LinphonePresenceBasicStatusOpen) { + add = true; + } - // Do not add the contact directly if we set some filter - if ([ContactSelection getSipFilter] || [ContactSelection emailFilterEnabled]) { - add = false; - } - if ([FastAddressBook contactHasValidSipDomain:contact]) { - add = true; - } - if (contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(contact.friend)) == LinphonePresenceBasicStatusOpen){ - add = true; - } - - - if (!add && [ContactSelection emailFilterEnabled]) { - // Add this contact if it has an email - add = (contact.emails.count > 0); - } + if (!add && [ContactSelection emailFilterEnabled]) { + // Add this contact if it has an email + add = (contact.emails.count > 0); + } - NSMutableString *name = [self displayNameForContact:contact] - ? [[NSMutableString alloc] initWithString:[self displayNameForContact:contact]] - : nil; - if (add && name != nil) { - NSString *firstChar = [[name substringToIndex:1] uppercaseString]; + NSMutableString *name = + [self displayNameForContact:contact] + ? [[NSMutableString alloc] + initWithString: + [self displayNameForContact:contact]] + : nil; + if (add && name != nil) { + NSString *firstChar = + [[name substringToIndex:1] uppercaseString]; - // Put in correct subAr - if ([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') { - firstChar = @"#"; - } - NSMutableArray *subAr = [addressBookMap objectForKey:firstChar]; - if (subAr == nil) { - subAr = [[NSMutableArray alloc] init]; - [addressBookMap insertObject:subAr forKey:firstChar selector:@selector(caseInsensitiveCompare:)]; - } - NSUInteger idx = [subAr indexOfObject:contact - inSortedRange:(NSRange){0, subAr.count} - options:NSBinarySearchingInsertionIndex - usingComparator:^NSComparisonResult(Contact* _Nonnull obj1, Contact* _Nonnull obj2) { - return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2]options:NSCaseInsensitiveSearch]; - }]; - if (![subAr containsObject:contact]) { - [subAr insertObject:contact atIndex:idx]; - } - } - } - [super loadData]; + // Put in correct subAr + if ([firstChar characterAtIndex:0] < 'A' || + [firstChar characterAtIndex:0] > 'Z') { + firstChar = @"#"; + } + NSMutableArray *subAr = + [addressBookMap objectForKey:firstChar]; + if (subAr == nil) { + subAr = [[NSMutableArray alloc] init]; + [addressBookMap + insertObject:subAr + forKey:firstChar + selector:@selector(caseInsensitiveCompare:)]; + } + NSUInteger idx = [subAr + indexOfObject:contact + inSortedRange:(NSRange){0, subAr.count} + options:NSBinarySearchingInsertionIndex + usingComparator:^NSComparisonResult( + Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] + compare:[self displayNameForContact:obj2] + options:NSCaseInsensitiveSearch]; + }]; + if (![subAr containsObject:contact]) { + [subAr insertObject:contact atIndex:idx]; + } + } + } + } + [super loadData]; - // since we refresh the tableview, we must perform this on main thread - dispatch_async(dispatch_get_main_queue(), ^(void) { - if (IPAD) { - if (!([self totalNumberOfItems] > 0)) { - ContactDetailsView *view = VIEW(ContactDetailsView); - [view setContact:nil]; - } - } - }); - } - _ongoing = FALSE; + // since we refresh the tableview, we must perform this on main + // thread + dispatch_async(dispatch_get_main_queue(), ^(void) { + if (IPAD) { + if (!([self totalNumberOfItems] > 0)) { + ContactDetailsView *view = VIEW(ContactDetailsView); + [view setContact:nil]; + } + } + }); + } + _ongoing = FALSE; } - (void)loadSearchedData { @@ -218,66 +246,94 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { NSMutableArray *subArContain = [NSMutableArray new]; [addressBookMap insertObject:subAr forKey:@"" selector:@selector(caseInsensitiveCompare:)]; for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; - BOOL add = true; - // Do not add the contact directly if we set some filter - if ([ContactSelection getSipFilter] || [ContactSelection emailFilterEnabled]) { - add = false; - } - NSString* filter = [ContactSelection getNameOrEmailFilter]; - if ([FastAddressBook contactHasValidSipDomain:contact]) { - add = true; - } - if (contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(contact.friend)) == LinphonePresenceBasicStatusOpen){ - add = true; - } - - - if (!add && [ContactSelection emailFilterEnabled]) { - // Add this contact if it has an email - add = (contact.emails.count > 0); - } - NSInteger idx_begin = -1; - NSInteger idx_sort = - 1; - NSMutableString *name = [self displayNameForContact:contact] - ? [[NSMutableString alloc] initWithString:[self displayNameForContact:contact]] - : nil; - if (add && name != nil) { - if ([[contact displayName] rangeOfString:filter options:NSCaseInsensitiveSearch].location == 0) { - if(![subArBegin containsObject:contact]) { - idx_begin = idx_begin + 1; - [subArBegin insertObject:contact atIndex:idx_begin]; - } - } else if([[contact displayName] rangeOfString:filter options:NSCaseInsensitiveSearch].location != NSNotFound) { - if(![subArContain containsObject:contact]) { - idx_sort = idx_sort + 1; - [subArContain insertObject:contact atIndex:idx_sort]; - } - } - } - } - [subArBegin sortUsingComparator:^NSComparisonResult(Contact* _Nonnull obj1, Contact* _Nonnull obj2) { - return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2]options:NSCaseInsensitiveSearch]; - }]; - - [subArContain sortUsingComparator:^NSComparisonResult(Contact* _Nonnull obj1, Contact* _Nonnull obj2) { - return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2]options:NSCaseInsensitiveSearch]; - }]; + @synchronized( + LinphoneManager.instance.fastAddressBook.addressBookMap) { + Contact *contact = + [LinphoneManager.instance.fastAddressBook.addressBookMap + objectForKey:addr]; - [subAr addObjectsFromArray:subArBegin]; - [subAr addObjectsFromArray:subArContain]; - [super loadData]; - - // since we refresh the tableview, we must perform this on main thread - dispatch_async(dispatch_get_main_queue(), ^(void) { - if (IPAD) { - if (!([self totalNumberOfItems] > 0)) { - ContactDetailsView *view = VIEW(ContactDetailsView); - [view setContact:nil]; - } - } - }); - } + BOOL add = true; + // Do not add the contact directly if we set some filter + if ([ContactSelection getSipFilter] || + [ContactSelection emailFilterEnabled]) { + add = false; + } + NSString *filter = [ContactSelection getNameOrEmailFilter]; + if ([FastAddressBook contactHasValidSipDomain:contact]) { + add = true; + } + if (contact.friend && + linphone_presence_model_get_basic_status( + linphone_friend_get_presence_model( + contact.friend)) == + LinphonePresenceBasicStatusOpen) { + add = true; + } + + if (!add && [ContactSelection emailFilterEnabled]) { + // Add this contact if it has an email + add = (contact.emails.count > 0); + } + NSInteger idx_begin = -1; + NSInteger idx_sort = -1; + NSMutableString *name = + [self displayNameForContact:contact] + ? [[NSMutableString alloc] + initWithString: + [self displayNameForContact:contact]] + : nil; + if (add && name != nil) { + if ([[contact displayName] + rangeOfString:filter + options:NSCaseInsensitiveSearch] + .location == 0) { + if (![subArBegin containsObject:contact]) { + idx_begin = idx_begin + 1; + [subArBegin insertObject:contact atIndex:idx_begin]; + } + } else if ([[contact displayName] + rangeOfString:filter + options:NSCaseInsensitiveSearch] + .location != NSNotFound) { + if (![subArContain containsObject:contact]) { + idx_sort = idx_sort + 1; + [subArContain insertObject:contact atIndex:idx_sort]; + } + } + } + } + } + [subArBegin + sortUsingComparator:^NSComparisonResult( + Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] + compare:[self displayNameForContact:obj2] + options:NSCaseInsensitiveSearch]; + }]; + + [subArContain + sortUsingComparator:^NSComparisonResult( + Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] + compare:[self displayNameForContact:obj2] + options:NSCaseInsensitiveSearch]; + }]; + + [subAr addObjectsFromArray:subArBegin]; + [subAr addObjectsFromArray:subArContain]; + [super loadData]; + + // since we refresh the tableview, we must perform this on main + // thread + dispatch_async(dispatch_get_main_queue(), ^(void) { + if (IPAD) { + if (!([self totalNumberOfItems] > 0)) { + ContactDetailsView *view = VIEW(ContactDetailsView); + [view setContact:nil]; + } + } + }); + } } @@ -365,17 +421,20 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } UIContactCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell setContact:NULL]; - [[LinphoneManager.instance fastAddressBook] removeContact:contact]; - [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] - withRowAnimation:UITableViewRowAnimationFade]; - [tableView endUpdates]; + [[LinphoneManager.instance fastAddressBook] + deleteContact:contact]; + [tableView + deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] + withRowAnimation:UITableViewRowAnimationFade]; + [tableView endUpdates]; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; - [self loadData]; - } + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; + [self loadData]; + } } - (void)removeSelectionUsing:(void (^)(NSIndexPath *))remover { @@ -391,12 +450,13 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } UIContactCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell setContact:NULL]; - [[LinphoneManager.instance fastAddressBook] removeContact:contact]; + [[LinphoneManager.instance fastAddressBook] deleteContact:contact]; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; }]; } diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index afafdb147..4e56fbac1 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -91,47 +91,56 @@ if (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription || PhoneMainView.instance.currentView == ContactDetailsView.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; - } - } + [instance.fastAddressBook reloadAllContacts]; + 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); + LinphoneCall *call = linphone_core_get_current_call(LC); - if (call) { - if (call == instance->currentCallContextBeforeGoingBackground.call) { - const LinphoneCallParams *params = linphone_call_get_current_params(call); - if (linphone_call_params_video_enabled(params)) { - linphone_call_enable_camera(call, instance->currentCallContextBeforeGoingBackground.cameraIsEnabled); - } - instance->currentCallContextBeforeGoingBackground.call = 0; - } else if (linphone_call_get_state(call) == LinphoneCallIncomingReceived) { - LinphoneCallAppData *data = (__bridge LinphoneCallAppData *)linphone_call_get_user_data(call); - if (data && data->timer) { - [data->timer invalidate]; - data->timer = nil; - } - if ((floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)) { - if ([LinphoneManager.instance lpConfigBoolForKey:@"autoanswer_notif_preference"]) { - linphone_call_accept(call); - [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; - } else { - [PhoneMainView.instance displayIncomingCall:call]; - } - } else if (linphone_core_get_calls_nb(LC) > 1) { - [PhoneMainView.instance displayIncomingCall:call]; - } + if (call) { + if (call == instance->currentCallContextBeforeGoingBackground.call) { + const LinphoneCallParams *params = + linphone_call_get_current_params(call); + if (linphone_call_params_video_enabled(params)) { + linphone_call_enable_camera( + call, instance->currentCallContextBeforeGoingBackground + .cameraIsEnabled); + } + instance->currentCallContextBeforeGoingBackground.call = 0; + } else if (linphone_call_get_state(call) == + LinphoneCallIncomingReceived) { + LinphoneCallAppData *data = + (__bridge LinphoneCallAppData *)linphone_call_get_user_data( + call); + if (data && data->timer) { + [data->timer invalidate]; + data->timer = nil; + } + if ((floor(NSFoundationVersionNumber) <= + NSFoundationVersionNumber_iOS_9_x_Max)) { + if ([LinphoneManager.instance + lpConfigBoolForKey:@"autoanswer_notif_preference"]) { + linphone_call_accept(call); + [PhoneMainView.instance + changeCurrentView:CallView.compositeViewDescription]; + } else { + [PhoneMainView.instance displayIncomingCall:call]; + } + } else if (linphone_core_get_calls_nb(LC) > 1) { + [PhoneMainView.instance displayIncomingCall:call]; + } - // in this case, the ringing sound comes from the notification. - // To stop it we have to do the iOS7 ring fix... - [self fixRing]; - } - } - [LinphoneManager.instance.iapManager check]; + // in this case, the ringing sound comes from the notification. + // To stop it we have to do the iOS7 ring fix... + [self fixRing]; + } + } + [LinphoneManager.instance.iapManager check]; } #pragma deploymate push "ignored-api-availability" @@ -959,7 +968,7 @@ didInvalidatePushTokenForType:(NSString *)type { linphone_core_set_provisioning_uri(LC, [configURL UTF8String]); [LinphoneManager.instance destroyLinphoneCore]; [LinphoneManager.instance startLinphoneCore]; - [LinphoneManager.instance.fastAddressBook reload]; + [LinphoneManager.instance.fastAddressBook reloadAllContacts]; } #pragma mark - Prevent ImagePickerView from rotating diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 51909e9e1..c0d7e4d75 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -636,7 +636,7 @@ } } // reload address book to prepend proxy config domain to contacts' phone number - [[LinphoneManager.instance fastAddressBook] reload]; + [[LinphoneManager.instance fastAddressBook] reloadAllContacts]; } - (void)synchronizeCodecs:(const MSList *)codecs { diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index fa3f3ed25..c0375b55e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2166,10 +2166,10 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat [self destroyLinphoneCore]; [self createLinphoneCore]; // reload friends - [self.fastAddressBook reload]; + [self.fastAddressBook reloadAllContacts]; - // reset network state to trigger a new network connectivity assessment - linphone_core_set_network_reachable(theLinphoneCore, FALSE); + // reset network state to trigger a new network connectivity assessment + linphone_core_set_network_reachable(theLinphoneCore, FALSE); } static int comp_call_id(const LinphoneCall *call, const char *callid) { diff --git a/Classes/Utils/FastAddressBook.h b/Classes/Utils/FastAddressBook.h index 4db2bebe4..606cf1576 100644 --- a/Classes/Utils/FastAddressBook.h +++ b/Classes/Utils/FastAddressBook.h @@ -28,16 +28,20 @@ @property(readonly, nonatomic) NSMutableDictionary *addressBookMap; @property BOOL needToUpdate; -- (void)reload; -- (void)saveAddressBook; -- (int)removeContact:(Contact *)contact; +- (BOOL)reloadAllContacts; +//- (void)saveAddressBook; +- (BOOL)deleteContact:(Contact *)contact; +- (BOOL)deleteCNContact:(CNContact *)CNContact; +- (BOOL)deleteAllContacts; - (BOOL)saveContact:(Contact *)contact; +- (BOOL)saveCNContact:(CNContact *)CNContact contact:(Contact *)Contact; + (BOOL)isAuthorized; // TOOLS + (Contact *)getContactWithAddress:(const LinphoneAddress *)address; +- (CNContact *)getCNContactFromContact:(Contact *)acontact; + (UIImage *)imageForContact:(Contact *)contact; + (UIImage *)imageForAddress:(const LinphoneAddress *)addr; @@ -52,5 +56,6 @@ + (NSString *)normalizeSipURI:(NSString *)address; // should be removed + (NSString *)localizedLabel:(NSString *)label; +- (void)registerAddrsFor:(Contact *)contact; @end diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index e9cf29f9d..754092fc8 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -25,11 +25,11 @@ #import "Utils.h" @implementation FastAddressBook { - ABAddressBookRef addressBook; CNContactStore* store; } -static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context); +// static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef +// info, void *context); + (UIImage *)imageForContact:(Contact *)contact { @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { @@ -108,150 +108,171 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info } + (BOOL)isAuthorized { - return ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized; + return [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; } - (FastAddressBook *)init { if ((self = [super init]) != nil) { - _addressBookMap = [NSMutableDictionary dictionary]; - 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]; - LOGD(@"CNContactStore requesting authorization"); - [contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) { - LOGD(@"CNContactStore authorization granted"); - }]; - } else if([CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized) { - LOGD(@"CNContactStore authorization granted"); - } - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil]; - } - - return self; + store = [[CNContactStore alloc] init]; + _addressBookMap = [NSMutableDictionary dictionary]; + [self reloadAllContacts]; + } + self.needToUpdate = FALSE; + if (floor(NSFoundationVersionNumber) >= + NSFoundationVersionNumber_iOS_9_x_Max) { + if ([CNContactStore class]) { + // ios9 or later + if (store == NULL) + store = [[CNContactStore alloc] init]; + CNEntityType entityType = CNEntityTypeContacts; + if ([CNContactStore authorizationStatusForEntityType:entityType] == + CNAuthorizationStatusNotDetermined) { + LOGD(@"CNContactStore requesting authorization"); + [store requestAccessForEntityType:entityType + completionHandler:^(BOOL granted, + NSError *_Nullable error) { + LOGD(@"CNContactStore authorization granted"); + }]; + } else if ([CNContactStore + authorizationStatusForEntityType:entityType] == + CNAuthorizationStatusAuthorized) { + LOGD(@"CNContactStore authorization granted"); + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(updateAddressBook:) + name:CNContactStoreDidChangeNotification + object:nil]; + //[self reload]; + store = [[CNContactStore alloc] init]; + [self reloadAllContacts]; + } + } + return self; } -- (void)saveAddressBook { - if (addressBook != nil) { - if (!ABAddressBookSave(addressBook, nil)) { - LOGW(@"Couldn't save Address Book"); - } - } -} - -- (void)reload { - CFErrorRef error; - - // create if it doesn't exist - if (addressBook == nil) { - addressBook = ABAddressBookCreateWithOptions(NULL, &error); - } - - 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; - } - - ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(weakSelf)); - dispatch_async(dispatch_get_main_queue(), ^(void) { - [weakSelf loadData]; - }); - - }); - } else { - LOGE(@"Create AddressBook failed, reason: %@", [(__bridge NSError *)error localizedDescription]); - } +/*- (void)saveAddressBook { + if (addressBook != nil) { + if (!ABAddressBookSave(addressBook, nil)) { + LOGW(@"Couldn't save Address Book"); + } + } } +*/ -(void) updateAddressBook:(NSNotification*) notif { LOGD(@"address book has changed"); self.needToUpdate = TRUE; + //[self reloadAllContacts]; +} + +/*- (void)reload { + [self getAllContacts]; + LOGE(@"Create AddressBook failed"); + +} +*/ +- (BOOL)reloadAllContacts { + BOOL success = FALSE; + if ([CNContactStore class]) { + [_addressBookMap removeAllObjects]; + // iOS 9 or later + NSError *contactError; + [store + containersMatchingPredicate:[CNContainer + predicateForContainersWithIdentifiers:@[ + store.defaultContainerIdentifier + ]] + error:&contactError]; + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactFamilyNameKey, CNContactGivenNameKey, + CNContactPostalAddressesKey, CNContactIdentifierKey, + CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey, + CNInstantMessageAddressUsernameKey, CNContactImageDataKey + ]; + CNContactFetchRequest *request = + [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; + success = + [store enumerateContactsWithFetchRequest:request + error:&contactError + usingBlock:^(CNContact *__nonnull contact, + BOOL *__nonnull stop) { + if (contactError) { + NSLog(@"error fetching contacts %@", + contactError); + } else { + Contact *newContact = [[Contact alloc] + initWithCNContact:contact]; + [_addressBookMap setObject:newContact + forKey:contact]; + [self registerAddrsFor:newContact]; + } + }]; + // load Linphone friends + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + LinphoneFriendList *fl = lists->data; + const MSList *friends = linphone_friend_list_get_friends(fl); + while (friends) { + LinphoneFriend *f = friends->data; + // only append friends that are not native contacts (already added + // above) + if (linphone_friend_get_ref_key(f) == NULL) { + Contact *contact = [[Contact alloc] initWithFriend:f]; + [self registerAddrsFor:contact]; + } + friends = friends->next; + } + linphone_friend_list_update_subscriptions(fl); + lists = lists->next; + } + } + [NSNotificationCenter.defaultCenter + postNotificationName:kLinphoneAddressBookUpdate + object:self]; + return success; } - (void)registerAddrsFor:(Contact *)contact { - for (NSString *phone in contact.phoneNumbers) { - char *normalizedPhone = - linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); - NSString *name = - [FastAddressBook normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : phone]; - if (phone != NULL) { - [_addressBookMap setObject:contact forKey:(name ?: [FastAddressBook localizedLabel:phone])]; - } - if (normalizedPhone) - ms_free(normalizedPhone); - } - for (NSString *sip in contact.sipAddresses) { - [_addressBookMap setObject:contact forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; - } -} - -- (void)loadData { - @synchronized(_addressBookMap) { - ABAddressBookRevert(addressBook); - [_addressBookMap removeAllObjects]; - - // load native contacts - CFArrayRef lContacts = ABAddressBookCopyArrayOfAllPeople(addressBook); - CFIndex count = CFArrayGetCount(lContacts); - for (CFIndex idx = 0; idx < count; idx++) { - ABRecordRef lPerson = CFArrayGetValueAtIndex(lContacts, idx); - Contact *contact = [[Contact alloc] initWithPerson:lPerson]; - [self registerAddrsFor:contact]; - } - CFRelease(lContacts); - - // load Linphone friends - const MSList *lists = linphone_core_get_friends_lists(LC); - while (lists) { - LinphoneFriendList *fl = lists->data; - const MSList *friends = linphone_friend_list_get_friends(fl); - while (friends) { - LinphoneFriend *f = friends->data; - // only append friends that are not native contacts (already added above) - if (linphone_friend_get_ref_key(f) == NULL) { - Contact *contact = [[Contact alloc] initWithFriend:f]; - [self registerAddrsFor:contact]; - } - friends = friends->next; - } - linphone_friend_list_update_subscriptions(fl); - lists = lists->next; - } - } - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneAddressBookUpdate object:self]; + for (NSString *phone in contact.phones) { + char *normalizedPhone = linphone_proxy_config_normalize_phone_number( + linphone_core_get_default_proxy_config(LC), phone.UTF8String); + NSString *name = [FastAddressBook + normalizeSipURI:normalizedPhone + ? [NSString stringWithUTF8String:normalizedPhone] + : phone]; + if (phone != NULL) { + [_addressBookMap + setObject:contact + forKey:(name ?: [FastAddressBook localizedLabel:phone])]; + } + if (normalizedPhone) + ms_free(normalizedPhone); + } + for (NSString *sip in contact.sipAddresses) { + [_addressBookMap setObject:contact + forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; + } } void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) { FastAddressBook *fastAddressBook = (__bridge FastAddressBook *)context; - [fastAddressBook loadData]; -} - -- (void)dealloc { - ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self)); - CFRelease(addressBook); + [fastAddressBook reloadAllContacts]; } #pragma mark - Tools + (NSString *)localizedLabel:(NSString *)label { if (label != nil) { - return CFBridgingRelease(ABAddressBookCopyLocalizedLabel((__bridge CFStringRef)(label))); - } - return @""; + return [CNLabeledValue localizedStringForLabel:label]; + } + return @""; } + (BOOL)contactHasValidSipDomain:(Contact *)contact { if (contact == nil) return NO; - // Check if one of the contact' sip URI matches the expected SIP filter NSString *domain = LinphoneManager.instance.contactFilter; @@ -317,60 +338,103 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void return ret; } -- (int)removeContact:(Contact *)contact { - // Remove contact from book - @synchronized(_addressBookMap) { - if (contact.person && ABRecordGetRecordID(contact.person) != kABRecordInvalidID) { - CFErrorRef error = NULL; - ABAddressBookRemoveRecord(addressBook, contact.person, (CFErrorRef *)&error); - if (error != NULL) { - LOGE(@"Remove contact %p: Fail(%@)", contact, [(__bridge NSError *)error localizedDescription]); - } else { - LOGI(@"Remove contact %p: Success!", contact); - } - contact = NULL; - // Save address book - error = NULL; - ABAddressBookSave(addressBook, (CFErrorRef *)&error); +- (BOOL)deleteContact:(Contact *)contact { + return [self deleteCNContact:contact.person]; +} - // TODO: stop reloading the whole address book but just clear the removed entries! - [self loadData]; +- (CNContact *)getCNContactFromContact:(Contact *)acontact { + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPostalAddressesKey, + CNContactIdentifierKey, CNContactInstantMessageAddressesKey, + CNInstantMessageAddressUsernameKey, CNContactImageDataKey + ]; + CNMutableContact *mCNContact = + [[store unifiedContactWithIdentifier:acontact.identifier + keysToFetch:keysToFetch + error:nil] mutableCopy]; + return mCNContact; +} - if (error != NULL) { - LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]); - } else { - LOGI(@"Save AddressBook: Success!"); - } - return error ? -1 : 0; - } - return -2; - } +- (BOOL)deleteCNContact:(CNContact *)contact { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + [saveRequest deleteContact:[contact mutableCopy]]; + @try { + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); + [self reloadAllContacts]; + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; + } + [self reloadAllContacts]; + return TRUE; +} + +- (BOOL)deleteAllContacts { + NSArray *keys = @[ CNContactPhoneNumbersKey ]; + NSString *containerId = store.defaultContainerIdentifier; + NSPredicate *predicate = + [CNContact predicateForContactsInContainerWithIdentifier:containerId]; + NSError *error; + NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate + keysToFetch:keys + error:&error]; + if (error) { + NSLog(@"error fetching contacts %@", error); + return FALSE; + } else { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + for (CNContact *contact in cnContacts) { + [saveRequest deleteContact:[contact mutableCopy]]; + } + @try { + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; + } + NSLog(@"Deleted contacts %lu", cnContacts.count); + } + return TRUE; } - (BOOL)saveContact:(Contact *)contact { - @synchronized(_addressBookMap) { - CFErrorRef error = NULL; - if (ABRecordGetRecordID(contact.person) == kABRecordInvalidID) { - if (ABAddressBookAddRecord(addressBook, contact.person, (CFErrorRef *)&error)) { - LOGI(@"Add contact %p: Success!", contact.person); - } else { - LOGE(@"Add contact %p: Fail(%@)", contact.person, [(__bridge NSError *)error localizedDescription]); - return FALSE; - } - } + return [self saveCNContact:contact.person contact:contact]; +} - // Save address book - error = NULL; - if (ABAddressBookSave(addressBook, &error)) { - LOGI(@"Save AddressBook: Success!"); - } else { - LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]); - return FALSE; - } - [self reload]; +- (BOOL)saveCNContact:(CNContact *)cNContact contact:(Contact *)contact { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactInstantMessageAddressesKey, CNInstantMessageAddressUsernameKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPostalAddressesKey, + CNContactIdentifierKey, CNContactImageDataKey, CNContactNicknameKey + ]; + CNMutableContact *mCNContact = + [[store unifiedContactWithIdentifier:contact.identifier + keysToFetch:keysToFetch + error:nil] mutableCopy]; + [mCNContact setGivenName:contact.firstName]; + [mCNContact setFamilyName:contact.lastName]; + [mCNContact setNickname:contact.displayName]; + [mCNContact setPhoneNumbers:contact.person.phoneNumbers]; + [mCNContact setEmailAddresses:contact.person.emailAddresses]; + [mCNContact + setInstantMessageAddresses:contact.person.instantMessageAddresses]; + [mCNContact setImageData:UIImageJPEGRepresentation(contact.avatar, 0.9f)]; - return error == NULL; - } + [saveRequest updateContact:mCNContact]; + NSError *saveError; + @try { + NSLog(@"Success %d", + [store executeSaveRequest:saveRequest error:&saveError]); + [_addressBookMap setObject:contact forKey:cNContact]; + } @catch (NSException *exception) { + NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", + [exception description]); + return FALSE; + } + return TRUE; } @end diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index a016034c2..8c82a871f 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -150,11 +150,14 @@ linphone_core_set_file_transfer_server(lc, "https://www.linphone.org:444/lft.php"); // reload address book to prepend proxy config domain to contacts' phone number - [[[LinphoneManager instance] fastAddressBook] reload]; + [[[LinphoneManager instance] fastAddressBook] + reloadAllContacts]; - [self waitForRegistration]; - [[LinphoneManager instance] lpConfigSetInt:NO forKey:@"animations_preference"]; - } + [self waitForRegistration]; + [[LinphoneManager instance] + lpConfigSetInt:NO + forKey:@"animations_preference"]; + } } - (UITableView *)findTableView:(NSString *)table { diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index e7e66b662..f4e2c1c65 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -29,8 +29,6 @@ 228697C411AC29B800E9E0CA /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 228697C311AC29B800E9E0CA /* CFNetwork.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 22968A5F12F875C600588287 /* UISpeakerButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 22968A5E12F875C600588287 /* UISpeakerButton.m */; }; 22AA8B0113D83F6300B30535 /* UICamSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 22AA8B0013D83F6300B30535 /* UICamSwitch.m */; }; - 22B5EFA310CE50BD00777D97 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B5EFA210CE50BD00777D97 /* AddressBookUI.framework */; }; - 22B5F03510CE6B2F00777D97 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B5F03410CE6B2F00777D97 /* AddressBook.framework */; }; 22C755601317E59C007BC101 /* UIBluetoothButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 22C7555F1317E59C007BC101 /* UIBluetoothButton.m */; }; 22D1B68112A3E0BE001AE361 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 22D1B68012A3E0BE001AE361 /* libresolv.dylib */; }; 22E0A822111C44E100B04932 /* AboutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22E0A81C111C44E100B04932 /* AboutView.m */; }; @@ -41,6 +39,7 @@ 244523BE1E8D3A6C0037A187 /* chat_unsecure.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523BC1E8D3A6C0037A187 /* chat_unsecure.png */; }; 24A3459E1D95797700881A5C /* UIShopTableCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24A3459D1D95797700881A5C /* UIShopTableCell.xib */; }; 24A345A61D95798A00881A5C /* UIShopTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 24A345A51D95798A00881A5C /* UIShopTableCell.m */; }; + 24E1C7C01F9A235600D3F981 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1C7B91F9A235500D3F981 /* Contacts.framework */; }; 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; 340751971506459A00B89C47 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 340751961506459A00B89C47 /* CoreTelephony.framework */; }; 340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 340751E6150F38FD00B89C47 /* UIVideoButton.m */; }; @@ -828,20 +827,6 @@ remoteGlobalIDString = FAB8A0141CAC546A00C6DFC1; remoteInfo = KIFFrameworkConsumerTests; }; - 8C90F57A1F94A621003B86C4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8CD87D4C1EF5105800ACA260; - remoteInfo = LinphoneManager; - }; - 8C90F57C1F94A621003B86C4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8CD87D541EF5105900ACA260; - remoteInfo = LinphoneManagerTests; - }; F08F119119C09C6B007D70C2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -963,6 +948,7 @@ 24A3459D1D95797700881A5C /* UIShopTableCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UIShopTableCell.xib; sourceTree = ""; }; 24A345A51D95798A00881A5C /* UIShopTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIShopTableCell.m; sourceTree = ""; }; 24A345A71D95799900881A5C /* UIShopTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIShopTableCell.h; sourceTree = ""; }; + 24E1C7B91F9A235500D3F981 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* linphone_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linphone_Prefix.pch; sourceTree = ""; }; @@ -1863,6 +1849,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 24E1C7C01F9A235600D3F981 /* Contacts.framework in Frameworks */, 8C5BCED61EB3859300A9AAEF /* mediastreamer_voip.framework in Frameworks */, 8C2595DF1DEDCC8E007A6424 /* CallKit.framework in Frameworks */, 8C5BCED81EB3859300A9AAEF /* mssilk.framework in Frameworks */, @@ -1878,8 +1865,6 @@ 6334DDFA1BBAC97C00631900 /* libsqlite3.dylib in Frameworks */, 152F22361B15E889008C0621 /* libxml2.dylib in Frameworks */, 570742671D5A63DB004B9C84 /* StoreKit.framework in Frameworks */, - 22B5F03510CE6B2F00777D97 /* AddressBook.framework in Frameworks */, - 22B5EFA310CE50BD00777D97 /* AddressBookUI.framework in Frameworks */, 22405EEE1600B4E400B92522 /* AssetsLibrary.framework in Frameworks */, 2274402F106F335E006EC466 /* AudioToolbox.framework in Frameworks */, 224567C2107B968500F10948 /* AVFoundation.framework in Frameworks */, @@ -2225,6 +2210,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 24E1C7B91F9A235500D3F981 /* Contacts.framework */, 8C3EAA191EB8D9C300B732B6 /* linphonetester.framework */, 8C5BCEC61EB3859200A9AAEF /* bctoolbox-tester.framework */, 8C3EA9EF1EB8A78C00B732B6 /* msx264.framework */, @@ -2316,8 +2302,6 @@ 63058A071B4E816A00EFAE36 /* KIF.framework */, 633FC7C81CD7466400774B8B /* KIFFrameworkConsumer.app */, 633FC7CA1CD7466400774B8B /* KIFFrameworkConsumerTests.xctest */, - 8C90F57B1F94A621003B86C4 /* LinphoneManager.framework */, - 8C90F57D1F94A621003B86C4 /* LinphoneManagerTests.xctest */, ); name = Products; sourceTree = ""; @@ -3242,20 +3226,6 @@ remoteRef = 633FC7C91CD7466400774B8B /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 8CA26B501F7D31E700411264 /* LinphoneManager.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = LinphoneManager.framework; - remoteRef = 8CA26B4F1F7D31E700411264 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 8CA26B521F7D31E700411264 /* LinphoneManagerTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = LinphoneManagerTests.xctest; - remoteRef = 8CA26B511F7D31E700411264 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ From 8c0f1d2315412a2eb95dbfa86fabd87b15c0e5fe Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 9 Nov 2017 14:41:20 +0100 Subject: [PATCH 10/42] [CNContact] CNContact fix history logs contacts link --- Classes/Contact.m | 30 +++++++++++----- Classes/ContactDetailsTableView.m | 3 +- Classes/Utils/FastAddressBook.m | 17 +++++---- Classes/Utils/Utils.m | 58 +++++++++++++++++-------------- 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/Classes/Contact.m b/Classes/Contact.m index e143728fa..5b1b79e41 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -230,12 +230,20 @@ NSString *normSip = NULL; if (_person && ![sip isEqualToString:@" "]) { if ((index + 1) > [_person.instantMessageAddresses count]) { - normSip = - [FastAddressBook normalizeSipURI:[sip substringFromIndex:1]]; - CNInstantMessageAddress *cNSipMsgAddr = [ - [CNInstantMessageAddress alloc] - initWithUsername:[normSip componentsSeparatedByString:@"@"][0] - service:[normSip componentsSeparatedByString:@"@"][1]]; + if ([sip hasPrefix:@" "]) + normSip = [sip substringFromIndex:1]; + else + normSip = sip; + CNInstantMessageAddress *cNSipMsgAddr; + if ([normSip containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:[normSip componentsSeparatedByString:@"@"][0] + service:[normSip + componentsSeparatedByString:@"@"][1]]; + else + cNSipMsgAddr = + [[CNInstantMessageAddress alloc] initWithUsername:normSip + service:normSip]; CNLabeledValue *sipAddress = [CNLabeledValue labeledValueWithLabel:NULL value:cNSipMsgAddr]; NSMutableArray *> @@ -244,7 +252,8 @@ [_person setValue:tmpSipAddress forKey:CNContactInstantMessageAddressesKey]; ret = TRUE; - _sipAddresses[index] = [sip substringFromIndex:1]; + _sipAddresses[index] = normSip; + //_sipAddresses[index] = [sip substringFromIndex:1]; } else { normSip = sip; CNInstantMessageAddress *cNSipMsgAddr; @@ -272,7 +281,7 @@ } if (ret) { - _sipAddresses[index] = sip; + _sipAddresses[index] = [FastAddressBook normalizeSipURI:sip]; } return ret; } @@ -389,7 +398,10 @@ } } if (ret) { - [_sipAddresses addObject:sip]; + if ([sip hasPrefix:@" "]) + [_sipAddresses addObject:[sip substringFromIndex:1]]; + else + [_sipAddresses addObject:[FastAddressBook normalizeSipURI:sip]]; } return ret; } diff --git a/Classes/ContactDetailsTableView.m b/Classes/ContactDetailsTableView.m index bf44219bd..5cf4daa2d 100644 --- a/Classes/ContactDetailsTableView.m +++ b/Classes/ContactDetailsTableView.m @@ -196,7 +196,8 @@ value = _contact.emails[indexPath.row]; [cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress]; } - + if ([value hasPrefix:@" "]) + value = [value substringFromIndex:1]; [cell setAddress:value]; return cell; diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 754092fc8..7df7be63e 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -52,12 +52,17 @@ } + (Contact *)getContact:(NSString *)address { - if (LinphoneManager.instance.fastAddressBook != nil) { - @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { - return [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:address]; - } - } - return nil; + + for (id key in LinphoneManager.instance.fastAddressBook.addressBookMap) { + Contact *contact = + (Contact *)[LinphoneManager.instance.fastAddressBook.addressBookMap + objectForKey:key]; + if ([contact.sipAddresses count]) { + if ([contact.sipAddresses containsObject:address]) + return contact; + } + } + return nil; } + (Contact *)getContactWithAddress:(const LinphoneAddress *)address { diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index 843ed7313..f2c47a610 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -465,37 +465,41 @@ normvalue = value.UTF8String; } LinphoneAddress *addr = linphone_proxy_config_normalize_sip_uri(cfg, normvalue); - // first try to find a friend with the given address Contact *c = [FastAddressBook getContactWithAddress:addr]; - if (c && c.friend) { - LinphoneFriend *f = c.friend; - const LinphonePresenceModel *m = - f ? linphone_friend_get_presence_model_for_uri_or_tel(f, value.UTF8String) : NULL; - const char *contact = m ? linphone_presence_model_get_contact(m) : NULL; - if (contact) { - LinphoneAddress *contact_addr = linphone_address_new(contact); - if (contact_addr) { - linphone_address_destroy(addr); - return contact_addr; - } - } - } - // since user wants to escape plus, we assume it expects to have phone numbers by default - if (addr) { - if (cfg && (linphone_proxy_config_get_dial_escape_plus(cfg))) { - if (linphone_proxy_config_is_phone_number(cfg, normvalue)) { - linphone_address_set_username(addr, normvalue); - } - } else { - if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { - linphone_address_set_username(addr, value.UTF8String); - } - } - } + if (c && c.friend) { + LinphoneFriend *f = c.friend; + const LinphonePresenceModel *m = + f ? linphone_friend_get_presence_model_for_uri_or_tel( + f, value.UTF8String) + : NULL; + const char *contact = + m ? linphone_presence_model_get_contact(m) : NULL; + if (contact) { + LinphoneAddress *contact_addr = linphone_address_new(contact); + if (contact_addr) { + linphone_address_destroy(addr); + return contact_addr; + } + } + } - return addr; + // since user wants to escape plus, we assume it expects to have phone + // numbers by default + if (addr) { + if (cfg && (linphone_proxy_config_get_dial_escape_plus(cfg))) { + if (linphone_proxy_config_is_phone_number(cfg, normvalue)) { + linphone_address_set_username(addr, normvalue); + } + } else { + if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { + linphone_address_set_username(addr, value.UTF8String); + } + } + } + + return addr; } @end From ef10b65b12e9b20704f8f214e1a409b0d7e98bb5 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 9 Nov 2017 16:43:53 +0100 Subject: [PATCH 11/42] [CNContact] CNContact fix ChatConversationTableView crash on click new --- Classes/Utils/FastAddressBook.m | 18 ----------- Classes/Utils/Utils.m | 57 +++++++++++++++++---------------- 2 files changed, 29 insertions(+), 46 deletions(-) diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 7df7be63e..ba59c388d 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -156,27 +156,11 @@ return self; } -/*- (void)saveAddressBook { - if (addressBook != nil) { - if (!ABAddressBookSave(addressBook, nil)) { - LOGW(@"Couldn't save Address Book"); - } - } -} -*/ - -(void) updateAddressBook:(NSNotification*) notif { LOGD(@"address book has changed"); self.needToUpdate = TRUE; - //[self reloadAllContacts]; } -/*- (void)reload { - [self getAllContacts]; - LOGE(@"Create AddressBook failed"); - -} -*/ - (BOOL)reloadAllContacts { BOOL success = FALSE; if ([CNContactStore class]) { @@ -209,8 +193,6 @@ } else { Contact *newContact = [[Contact alloc] initWithCNContact:contact]; - [_addressBookMap setObject:newContact - forKey:contact]; [self registerAddrsFor:newContact]; } }]; diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index f2c47a610..5aaa54dcc 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -454,35 +454,36 @@ } + (LinphoneAddress *)normalizeSipOrPhoneAddress:(NSString *)value { - if (!value) { - return NULL; - } - LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(LC); - const char * normvalue; - if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { - normvalue = linphone_proxy_config_normalize_phone_number(cfg, value.UTF8String); - } else { - normvalue = value.UTF8String; - } - LinphoneAddress *addr = linphone_proxy_config_normalize_sip_uri(cfg, normvalue); - // first try to find a friend with the given address - Contact *c = [FastAddressBook getContactWithAddress:addr]; + if (!value || [value isEqualToString:@""]) { + return NULL; + } + LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(LC); + const char *normvalue; + if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { + normvalue = + linphone_proxy_config_normalize_phone_number(cfg, value.UTF8String); + } else { + normvalue = value.UTF8String; + } + LinphoneAddress *addr = + linphone_proxy_config_normalize_sip_uri(cfg, normvalue); + // first try to find a friend with the given address + Contact *c = [FastAddressBook getContactWithAddress:addr]; - if (c && c.friend) { - LinphoneFriend *f = c.friend; - const LinphonePresenceModel *m = - f ? linphone_friend_get_presence_model_for_uri_or_tel( - f, value.UTF8String) - : NULL; - const char *contact = - m ? linphone_presence_model_get_contact(m) : NULL; - if (contact) { - LinphoneAddress *contact_addr = linphone_address_new(contact); - if (contact_addr) { - linphone_address_destroy(addr); - return contact_addr; - } - } + if (c && c.friend) { + LinphoneFriend *f = c.friend; + const LinphonePresenceModel *m = + f ? linphone_friend_get_presence_model_for_uri_or_tel(f, + value.UTF8String) + : NULL; + const char *contact = m ? linphone_presence_model_get_contact(m) : NULL; + if (contact) { + LinphoneAddress *contact_addr = linphone_address_new(contact); + if (contact_addr) { + linphone_address_destroy(addr); + return contact_addr; + } + } } // since user wants to escape plus, we assume it expects to have phone From 4e7b5099543b8cfbe92b67f1c1fef6fafa19c5e4 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Fri, 10 Nov 2017 14:32:45 +0100 Subject: [PATCH 12/42] [CNContact] CNContact fix sip address display and chat searchlist --- Classes/Contact.m | 21 +++++++++------------ Classes/Utils/FastAddressBook.m | 19 +++++++------------ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/Classes/Contact.m b/Classes/Contact.m index 5b1b79e41..8ee7bbf82 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -236,10 +236,8 @@ normSip = sip; CNInstantMessageAddress *cNSipMsgAddr; if ([normSip containsString:@"@"]) - cNSipMsgAddr = [[CNInstantMessageAddress alloc] - initWithUsername:[normSip componentsSeparatedByString:@"@"][0] - service:[normSip - componentsSeparatedByString:@"@"][1]]; + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:normSip service:[normSip componentsSeparatedByString:@"@"][1]]; else cNSipMsgAddr = [[CNInstantMessageAddress alloc] initWithUsername:normSip @@ -253,15 +251,14 @@ forKey:CNContactInstantMessageAddressesKey]; ret = TRUE; _sipAddresses[index] = normSip; - //_sipAddresses[index] = [sip substringFromIndex:1]; } else { normSip = sip; CNInstantMessageAddress *cNSipMsgAddr; - if ([normSip containsString:@"@"]) - cNSipMsgAddr = [[CNInstantMessageAddress alloc] - initWithUsername:[normSip componentsSeparatedByString:@"@"][0] - service:[normSip - componentsSeparatedByString:@"@"][1]]; + if ([[FastAddressBook normalizeSipURI:normSip] containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:sip + service:[[FastAddressBook normalizeSipURI:normSip] + componentsSeparatedByString:@"@"][1]]; else cNSipMsgAddr = [[CNInstantMessageAddress alloc] initWithUsername:normSip @@ -281,7 +278,7 @@ } if (ret) { - _sipAddresses[index] = [FastAddressBook normalizeSipURI:sip]; + _sipAddresses[index] = sip; } return ret; } @@ -401,7 +398,7 @@ if ([sip hasPrefix:@" "]) [_sipAddresses addObject:[sip substringFromIndex:1]]; else - [_sipAddresses addObject:[FastAddressBook normalizeSipURI:sip]]; + [_sipAddresses addObject:sip]; } return ret; } diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index ba59c388d..eb1dbf93b 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -52,17 +52,12 @@ } + (Contact *)getContact:(NSString *)address { - - for (id key in LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = - (Contact *)[LinphoneManager.instance.fastAddressBook.addressBookMap - objectForKey:key]; - if ([contact.sipAddresses count]) { - if ([contact.sipAddresses containsObject:address]) - return contact; - } - } - return nil; + if (LinphoneManager.instance.fastAddressBook != nil) { + @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { + return [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:address]; + } + } + return nil; } + (Contact *)getContactWithAddress:(const LinphoneAddress *)address { @@ -415,12 +410,12 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void @try { NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:&saveError]); - [_addressBookMap setObject:contact forKey:cNContact]; } @catch (NSException *exception) { NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", [exception description]); return FALSE; } + [self reloadAllContacts]; return TRUE; } From c910192da56948f0c1052fbffbe89c92687780a9 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Fri, 10 Nov 2017 14:49:01 +0100 Subject: [PATCH 13/42] [CNContact] CNContact fix Contact detail edition add only one email/phone --- Classes/ContactDetailsTableView.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Classes/ContactDetailsTableView.m b/Classes/ContactDetailsTableView.m index 5cf4daa2d..97657c64e 100644 --- a/Classes/ContactDetailsTableView.m +++ b/Classes/ContactDetailsTableView.m @@ -75,12 +75,16 @@ - (void)addEntry:(UITableView *)tableview section:(NSInteger)section animated:(BOOL)animated value:(NSString *)value { bool added = FALSE; if (section == ContactSections_Number) { + if ([_contact.phones count] == + [_contact.person.phoneNumbers count]) added = [_contact addPhoneNumber:value]; } else if (section == ContactSections_Sip) { if ([_contact.sipAddresses count] == [_contact.person.instantMessageAddresses count]) added = [_contact addSipAddress:value]; } else if (section == ContactSections_Email) { + if ([_contact.emails count] == + [_contact.person.emailAddresses count]) added = [_contact addEmail:value]; } if (added) { From 87020ea918f2012c95eb2d755d0b98e4e0a0e76c Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Mon, 13 Nov 2017 11:47:03 +0100 Subject: [PATCH 14/42] [CNContact] CNContact clean fastAddressBook --- Classes/Utils/FastAddressBook.m | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index eb1dbf93b..29b101c92 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -28,9 +28,6 @@ CNContactStore* store; } -// static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef -// info, void *context); - + (UIImage *)imageForContact:(Contact *)contact { @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { UIImage *retImage = [contact avatar]; @@ -238,11 +235,6 @@ } } -void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) { - FastAddressBook *fastAddressBook = (__bridge FastAddressBook *)context; - [fastAddressBook reloadAllContacts]; -} - #pragma mark - Tools + (NSString *)localizedLabel:(NSString *)label { From 28b403383d745273aeb881c9ecc00ba9338b0e0a Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Mon, 13 Nov 2017 16:59:47 +0100 Subject: [PATCH 15/42] [CNContact] CNContact fix multiple contact edition crashes --- Classes/Contact.m | 20 ++++++++++------ Classes/ContactDetailsView.m | 5 +--- Classes/LinphoneManager.m | 10 ++++---- .../Base.lproj/UIChatBubblePhotoCell.strings | Bin 2366 -> 2870 bytes .../Base.lproj/UIChatBubbleTextCell.strings | Bin 1620 -> 2104 bytes Classes/Utils/FastAddressBook.m | 22 +++++++++++------- Resources/en.lproj/Localizable.strings | Bin 63436 -> 63890 bytes 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/Classes/Contact.m b/Classes/Contact.m index 8ee7bbf82..8fde471f9 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -468,12 +468,14 @@ - (BOOL)removeSipAddressAtIndex:(NSInteger)index { BOOL ret = FALSE; - if (_person) { + if (_person ) { NSMutableArray *> *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; - [tmpSipAddress removeObjectAtIndex:index]; - [_person setValue:tmpSipAddress - forKey:CNContactInstantMessageAddressesKey]; + if([tmpSipAddress count] > index){ + [tmpSipAddress removeObjectAtIndex:index]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + } ret = TRUE; } else { LinphoneAddress *addr = linphone_core_interpret_url( @@ -498,8 +500,10 @@ if (_person && _person.phoneNumbers.count > 0) { NSMutableArray *> *tmpPhoneNumbers = [_person.phoneNumbers mutableCopy]; - [tmpPhoneNumbers removeObjectAtIndex:index]; - [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + if([tmpPhoneNumbers count] > index){ + [tmpPhoneNumbers removeObjectAtIndex:index]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + } ret = TRUE; } else { const char *phone = ((NSString *)_phones[index]).UTF8String; @@ -517,12 +521,14 @@ - (BOOL)removeEmailAtIndex:(NSInteger)index { BOOL ret = FALSE; - if (_person) { + if (_person && _person.phoneNumbers.count > 0) { NSMutableArray *> *tmpEmailAddresses = [_person.emailAddresses mutableCopy]; + if([tmpEmailAddresses count] > index){ [tmpEmailAddresses removeObjectAtIndex:index]; [_person setValue:tmpEmailAddresses forKey:CNContactEmailAddressesKey]; + } ret = TRUE; } else { LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", diff --git a/Classes/ContactDetailsView.m b/Classes/ContactDetailsView.m index 16bccb61d..6d704500c 100644 --- a/Classes/ContactDetailsView.m +++ b/Classes/ContactDetailsView.m @@ -430,13 +430,10 @@ static UICompositeViewDescription *compositeDescription = nil; if (_tmpContact.emails != NULL) { while (_tmpContact.emails.count > nbEmail) { [_contact addEmail:_tmpContact.emails[nbEmail]]; - // [_contact - // addPhoneNumber:((CNLabeledValue*)_tmpContact.phoneNumbers[nbPhone]).value.stringValue]; nbEmail++; } } - [self saveData]; - //[self.tableController.tableView reloadData]; + // [self saveData]; } else { [LinphoneManager.instance.fastAddressBook deleteContact:_contact]; } diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index c0375b55e..8cdddd532 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2361,10 +2361,12 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { } const MSList *lists = linphone_core_get_friends_lists(LC); - while (lists) { - linphone_friend_list_enable_subscriptions( - lists->data, enabled && [LinphoneManager.instance lpConfigBoolForKey:@"use_rls_presence"]); - lists = lists->next; + if(lists != nil){ + while (lists) { + linphone_friend_list_enable_subscriptions( + lists->data, enabled && [LinphoneManager.instance lpConfigBoolForKey:@"use_rls_presence"]); + lists = lists->next; + } } } diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.strings b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.strings index bbc940d424f499501ce57e88299bea3e270ecca8..ba11c1c509fadfe0b855ac67bed4276d1b2b2433 100644 GIT binary patch delta 179 zcmdldv`uV+!sGxJfypJT0+XLH@lB3nQnEK;Fk#4I&}GPFNClFf422At3`z{v3ylW#LgPGZ*BsGz|%iK)TdhamuLS{OqJ&@=;vGzJee)3B+~ dn`o#yS%95qvH*+2L|UhEO2s$WY2q!l1-p&7i=b#h}l?1!QAUF?l1i;ba3g zmCZV=8jO>5Smh>5F)6SHF{CmiPHtpTjHqPrW^e%-SHR#5B>fmNfX1R4icN(c(CSo% X3a|qd7;J$~P+|a^$&dop&BXu!BKIEi delta 15 WcmdlXaD`{XDb~p%>>`ud*vkMfKm`B* diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 29b101c92..d8fd9e41a 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -388,16 +388,20 @@ [[store unifiedContactWithIdentifier:contact.identifier keysToFetch:keysToFetch error:nil] mutableCopy]; - [mCNContact setGivenName:contact.firstName]; - [mCNContact setFamilyName:contact.lastName]; - [mCNContact setNickname:contact.displayName]; - [mCNContact setPhoneNumbers:contact.person.phoneNumbers]; - [mCNContact setEmailAddresses:contact.person.emailAddresses]; - [mCNContact - setInstantMessageAddresses:contact.person.instantMessageAddresses]; - [mCNContact setImageData:UIImageJPEGRepresentation(contact.avatar, 0.9f)]; + if(mCNContact == NULL){ + [saveRequest addContact:[cNContact mutableCopy] toContainerWithIdentifier:nil]; + }else{ + [mCNContact setGivenName:contact.firstName]; + [mCNContact setFamilyName:contact.lastName]; + [mCNContact setNickname:contact.displayName]; + [mCNContact setPhoneNumbers:contact.person.phoneNumbers]; + [mCNContact setEmailAddresses:contact.person.emailAddresses]; + [mCNContact + setInstantMessageAddresses:contact.person.instantMessageAddresses]; + [mCNContact setImageData:UIImageJPEGRepresentation(contact.avatar, 0.9f)]; - [saveRequest updateContact:mCNContact]; + [saveRequest updateContact:mCNContact]; + } NSError *saveError; @try { NSLog(@"Success %d", diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 27ff2b32b38781752408000925d581107a031c30..2154467a9b397cc1617197233ede16f7ed315270 100644 GIT binary patch delta 1177 zcmbVLO=uHQ5PoZ7sc90E5VuK8H3q7e2(ePV)KZ}b4?*-`YE5mLKQWkYODY8+ioJ;F zMf^m15Y0)UcnCfZ;-P{<@en+UhZ5Q*mYkYuvY~i#-fC)UPYKI1J8!=E=FNPw`HJpw zRhRpE!Zgg1Y=%v<6pOH1_;Eapp;H6M_u2TpKKTG&I=5v+VAKu&B?k|T)+N3inw8*C zjVO$mF{WO@^thgHTz%T*j1fhOo+#NEyFs*G=3!@;2jOJz{{N!5XbSOY@~sWZ?InKa z?qvrq;5^@)cXZ&(;s6%1W;}W^2){ds&F5yk%es-bcJhVno5S4q>9q$#xsH7bn_@Sq zNCeW)-h*RIVIwR-z9^=UZNy`+dXHhPB4e;Cx=0)_s!2wer`=OVb-8T!N(`m3pvVw}|}yHuBjFR(nD`R~nY^e$Iu!OBpWJ4*z#O z7UyKmA6KIyrXxLJ{n!m(rV|?#Lj&{od=j~mS>$N`hs=>(m`Y}fFa|t$Xh)VG;z!p% zOKtY-Jey#X+MH6_R9c?fpT4#0$Yn3|dk?EMRib$Qgz_G;8=(&;2s z&**Rvq@SoZ?@2V+$vWHByl*++3jgs%yBH;6dm+bd2a(PZcGqb z^eWCvrr0$qI)U}adk~JfF_)8eU|#=>A)1pgRCWAql@r?)ws5M@#Hj|4<}#A!0?ji; zUy5nG Date: Tue, 14 Nov 2017 14:52:14 +0100 Subject: [PATCH 16/42] Better sound management --- Classes/LinphoneManager.m | 2 -- Classes/SideMenuTableView.m | 4 +++- submodules/linphone | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 8cdddd532..106ce644e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -828,8 +828,6 @@ static void linphone_iphone_display_status(struct _LinphoneCore *lc, const char // furthermore it introduces a bug when calling multiple times since route may not be // reconfigured between cause leading to bluetooth being disabled while it should not _bluetoothEnabled = FALSE; - /*IOS specific*/ - linphone_core_start_dtmf_stream(theLinphoneCore); } if (incallBgTask) { diff --git a/Classes/SideMenuTableView.m b/Classes/SideMenuTableView.m index 0f7e82630..223908d4e 100644 --- a/Classes/SideMenuTableView.m +++ b/Classes/SideMenuTableView.m @@ -6,6 +6,8 @@ // // +#import "linphone/core_utils.h" + #import "SideMenuTableView.h" #import "Utils.h" @@ -37,7 +39,7 @@ } - (void)viewWillAppear:(BOOL)animated { - linphone_core_stop_dtmf(LC); + linphone_core_stop_dtmf_stream(LC); [super viewWillAppear:animated]; _sideMenuEntries = [[NSMutableArray alloc] init]; diff --git a/submodules/linphone b/submodules/linphone index 145b05ee8..3d923a875 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 145b05ee8dddeca71518f327a69b474ac048f77a +Subproject commit 3d923a8759d93304e478228f6f296114372a3ba6 From 5c534def046cf0a0e1d8c2fb332f11e46f11e8e5 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 14 Nov 2017 15:54:34 +0100 Subject: [PATCH 17/42] Fix resend in chat conversation --- .../Base.lproj/UIChatBubbleTextCell.xib | 31 ++----- Classes/LinphoneUI/UIChatBubblePhotoCell.m | 2 +- Classes/LinphoneUI/UIChatBubbleTextCell.h | 6 +- Classes/LinphoneUI/UIChatBubbleTextCell.m | 81 ++++++++++--------- 4 files changed, 55 insertions(+), 65 deletions(-) diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib index 4d7e89297..406aae959 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib @@ -1,11 +1,11 @@ - - + + - + @@ -20,17 +20,10 @@ - - - - - - - @@ -59,11 +52,6 @@ - - - - - @@ -94,12 +82,11 @@ - + + + - - - @@ -110,14 +97,8 @@ - - - - - - diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index b85a67c4e..f6d210880 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -172,7 +172,7 @@ } else if (_cancelButton.hidden == NO) { [self onCancelClick:event]; } else { - [super onResendClick:event]; + [super onResend]; } } diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.h b/Classes/LinphoneUI/UIChatBubbleTextCell.h index 9c3d71762..56f108874 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.h +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.h @@ -29,7 +29,6 @@ @property(nonatomic, weak) IBOutlet UIImageView *backgroundColorImage; @property(nonatomic, weak) IBOutlet UIRoundedImageView *avatarImage; @property(nonatomic, weak) IBOutlet UILabel *contactDateLabel; -@property(nonatomic, weak) IBOutlet UIImageView *statusErrorImage; @property(weak, nonatomic) IBOutlet UIActivityIndicatorView *statusInProgressSpinner; @property(nonatomic, weak) IBOutlet UITextViewNoDefine *messageText; @property(weak, nonatomic) IBOutlet UIImageView *bottomBarColor; @@ -44,8 +43,9 @@ - (void)setChatMessage:(LinphoneChatMessage *)message; -- (IBAction)onDeleteClick:(id)event; -- (IBAction)onResendClick:(id)event; +- (void)onDelete; +- (void)onResend; +- (void)onLime; - (void)update; - (void)displayImdmStatus:(LinphoneChatMessageState)state; diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index 646fbeaf2..8a815ecce 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -40,6 +40,21 @@ [self addSubview:sub]; } } + + UITapGestureRecognizer *limeRecognizer = + [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onLime)]; + limeRecognizer.numberOfTapsRequired = 1; + [_LIMEKO addGestureRecognizer:limeRecognizer]; + _LIMEKO.userInteractionEnabled = YES; + + UITapGestureRecognizer *resendRecognizer = + [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)]; + resendRecognizer.numberOfTapsRequired = 1; + [_imdmIcon addGestureRecognizer:resendRecognizer]; + _imdmIcon.userInteractionEnabled = YES; + [_imdmLabel addGestureRecognizer:resendRecognizer]; + _imdmLabel.userInteractionEnabled = YES; + return self; } @@ -135,13 +150,10 @@ _contactDateLabel.textColor = [UIColor colorWithPatternImage:_backgroundColorImage.image]; if (outgoing && state == LinphoneChatMessageStateInProgress) { - _statusErrorImage.hidden = YES; [_statusInProgressSpinner startAnimating]; } else if (!outgoing && state == LinphoneChatMessageStateFileTransferError) { - _statusErrorImage.hidden = NO; [_statusInProgressSpinner stopAnimating]; } else { - _statusErrorImage.hidden = YES; [_statusInProgressSpinner stopAnimating]; } @@ -195,7 +207,7 @@ #pragma mark - Action Functions -- (IBAction)onDeleteClick:(id)event { +- (void)onDelete { if (_message != NULL) { UITableView *tableView = VIEW(ChatConversationView).tableController.tableView; NSIndexPath *indexPath = [tableView indexPathForCell:self]; @@ -205,45 +217,42 @@ } } -- (IBAction)onResendClick:(id)event { - if (!_LIMEKO.hidden) { +- (void)onLime { + if (!_LIMEKO.hidden) [self displayLIMEWarning]; - return; - } +} +- (void)onResend { if (_message == nil || !linphone_chat_message_is_outgoing(_message)) return; LinphoneChatMessageState state = linphone_chat_message_get_state(_message); - if (state == LinphoneChatMessageStateNotDelivered || state == LinphoneChatMessageStateFileTransferError) { - if (linphone_chat_message_get_file_transfer_information(_message) != NULL) { - NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message]; - NSNumber *uploadQuality =[LinphoneManager getMessageAppDataForKey:@"uploadQuality" inMessage:_message]; - - NSURL *imageUrl = [NSURL URLWithString:localImage]; + if (state != LinphoneChatMessageStateNotDelivered && state != LinphoneChatMessageStateFileTransferError) + return; - [self onDeleteClick:nil]; - - [LinphoneManager.instance.photoLibrary assetForURL:imageUrl - resultBlock:^(ALAsset *asset) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), - ^(void) { - UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]]; - [_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; - }); - } - failureBlock:^(NSError *error) { - LOGE(@"Can't read image"); - }]; - } else { - [self onDeleteClick:nil]; - - double delayInSeconds = 0.4; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { - [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil]; - }); - } + if (linphone_chat_message_get_file_transfer_information(_message) != NULL) { + NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message]; + NSNumber *uploadQuality =[LinphoneManager getMessageAppDataForKey:@"uploadQuality" inMessage:_message]; + NSURL *imageUrl = [NSURL URLWithString:localImage]; + [self onDelete]; + [LinphoneManager.instance.photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]]; + [_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } else { + [self onDelete]; + double delayInSeconds = 0.4; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { + [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil]; + }); } } #pragma mark - State changed handling From b2df11512eb53f6e84b418f51fe3da4eea563934 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 14 Nov 2017 17:12:29 +0100 Subject: [PATCH 18/42] do not crash if domain as a port in 'use sip account' --- Classes/AssistantView.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/AssistantView.m b/Classes/AssistantView.m index 4ed9c7420..7048d0d39 100644 --- a/Classes/AssistantView.m +++ b/Classes/AssistantView.m @@ -1324,8 +1324,10 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun NSString *pwd = [self findTextField:ViewElement_Password].text; LinphoneProxyConfig *config = linphone_core_create_proxy_config(LC); LinphoneAddress *addr = linphone_address_new(NULL); + LinphoneAddress *tmpAddr = linphone_address_new([NSString stringWithFormat:@"sip:%@",domain].UTF8String); linphone_address_set_username(addr, username.UTF8String); - linphone_address_set_domain(addr, domain.UTF8String); + linphone_address_set_port(addr, linphone_address_get_port(tmpAddr)); + linphone_address_set_domain(addr, linphone_address_get_domain(tmpAddr)); if (displayName && ![displayName isEqualToString:@""]) { linphone_address_set_display_name(addr, displayName.UTF8String); } @@ -1359,6 +1361,7 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun ); linphone_core_add_auth_info(LC, info); linphone_address_unref(addr); + linphone_address_unref(tmpAddr); if (config) { [[LinphoneManager instance] configurePushTokenForProxyConfig:config]; From 99cd73a52c572681d1016e4e68857e4640a88c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Wed, 15 Nov 2017 11:58:40 +0100 Subject: [PATCH 19/42] Update linphone submodule (Fills private data in LinphoneChatMessages with zeros --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index 3d923a875..bd08e5940 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 3d923a8759d93304e478228f6f296114372a3ba6 +Subproject commit bd08e5940c7358a945fff0d0e47678440a1b4ba5 From 20879f9894435cbeae13f4947edd70d025a7f582 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 16 Nov 2017 14:50:58 +0100 Subject: [PATCH 20/42] fix cast blocking build --- Classes/LinphoneUI/UIChatBubbleTextCell.m | 6 ++++-- Classes/Utils/FastAddressBook.m | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index 8a815ecce..88d03143e 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -46,13 +46,15 @@ limeRecognizer.numberOfTapsRequired = 1; [_LIMEKO addGestureRecognizer:limeRecognizer]; _LIMEKO.userInteractionEnabled = YES; - UITapGestureRecognizer *resendRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)]; resendRecognizer.numberOfTapsRequired = 1; [_imdmIcon addGestureRecognizer:resendRecognizer]; _imdmIcon.userInteractionEnabled = YES; - [_imdmLabel addGestureRecognizer:resendRecognizer]; + UITapGestureRecognizer *resendRecognizer2 = + [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)]; + resendRecognizer2.numberOfTapsRequired = 1; + [_imdmLabel addGestureRecognizer:resendRecognizer2]; _imdmLabel.userInteractionEnabled = YES; return self; diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index d8fd9e41a..7ea1cb9c8 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -367,7 +367,7 @@ NSLog(@"description = %@", [exception description]); return FALSE; } - NSLog(@"Deleted contacts %lu", cnContacts.count); + NSLog(@"Deleted contacts %lu", (unsigned long)cnContacts.count); } return TRUE; } From 4f42d32501620066f7c0064b60ba2f154674973b Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Thu, 16 Nov 2017 15:01:58 +0100 Subject: [PATCH 21/42] remove useless if --- Classes/LinphoneManager.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 106ce644e..5aa090def 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2359,12 +2359,10 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { } const MSList *lists = linphone_core_get_friends_lists(LC); - if(lists != nil){ - while (lists) { - linphone_friend_list_enable_subscriptions( - lists->data, enabled && [LinphoneManager.instance lpConfigBoolForKey:@"use_rls_presence"]); - lists = lists->next; - } + while (lists) { + linphone_friend_list_enable_subscriptions( + lists->data, enabled && [LinphoneManager.instance lpConfigBoolForKey:@"use_rls_presence"]); + lists = lists->next; } } From 9fdc05c863b757e44c2cfc48d0a721a4a3e9ede6 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Wed, 15 Nov 2017 15:30:18 +0100 Subject: [PATCH 22/42] [ChatPhotoCell] remove sendImageError icons on chatImageCell to avoid crash --- .../Base.lproj/UIChatBubblePhotoCell.xib | 18 +++--------------- Classes/LinphoneUI/UIContactDetailsCell.m | 1 + submodules/linphone | 2 +- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib index 409ea31d6..f6e957883 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib @@ -1,11 +1,11 @@ - - + + - + @@ -26,7 +26,6 @@ - @@ -113,11 +112,6 @@ - - - - - @@ -163,7 +157,6 @@ - @@ -172,9 +165,4 @@ - - - - - diff --git a/Classes/LinphoneUI/UIContactDetailsCell.m b/Classes/LinphoneUI/UIContactDetailsCell.m index 39b25a77d..76326c098 100644 --- a/Classes/LinphoneUI/UIContactDetailsCell.m +++ b/Classes/LinphoneUI/UIContactDetailsCell.m @@ -128,6 +128,7 @@ - (IBAction)onCallClick:(id)event { LinphoneAddress *addr = [LinphoneUtils normalizeSipOrPhoneAddress:_addressLabel.text]; + LOGE(@"=====>>>> onCallClick() : %@ ", [NSString stringWithUTF8String:linphone_address_as_string(addr)] ); [LinphoneManager.instance call:addr]; if (addr) linphone_address_destroy(addr); diff --git a/submodules/linphone b/submodules/linphone index bd08e5940..145b05ee8 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit bd08e5940c7358a945fff0d0e47678440a1b4ba5 +Subproject commit 145b05ee8dddeca71518f327a69b474ac048f77a From 10be6d0be79810c5e8e3acb5065a7f9c1f4c039f Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 16 Nov 2017 15:56:47 +0100 Subject: [PATCH 23/42] [CNContact] fix presence subscription on save/update contact --- Classes/Utils/FastAddressBook.m | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 7ea1cb9c8..774b33415 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -409,10 +409,31 @@ } @catch (NSException *exception) { NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", [exception description]); + [self updateFriend:contact]; return FALSE; } [self reloadAllContacts]; return TRUE; } +-(void)updateFriend:(Contact*) contact{ + bctbx_list_t *phonesList = linphone_friend_get_phone_numbers(contact.friend); + for (NSString *phone in contact.phones) { + if(!(bctbx_list_find(phonesList, [phone UTF8String]))){ + linphone_friend_edit(contact.friend); + linphone_friend_add_phone_number(contact.friend, [phone UTF8String]); + linphone_friend_enable_subscribes(contact.friend, TRUE); + linphone_friend_done(contact.friend); + } + } + + BOOL enabled = [LinphoneManager.instance lpConfigBoolForKey:@"use_rls_presence"]; + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + linphone_friend_list_enable_subscriptions(lists->data, FALSE); + linphone_friend_list_enable_subscriptions(lists->data, enabled); + linphone_friend_list_update_subscriptions(lists->data); + lists = lists->next; + } +} @end From 98446e09855107b37f7f2e033ced3d08478554e7 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 16 Nov 2017 16:01:15 +0100 Subject: [PATCH 24/42] [gsu] submodule linphone updated --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index 145b05ee8..bd08e5940 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 145b05ee8dddeca71518f327a69b474ac048f77a +Subproject commit bd08e5940c7358a945fff0d0e47678440a1b4ba5 From 90f100a4cc9e214fe89d06ed88264928845f1404 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 16 Nov 2017 16:18:05 +0100 Subject: [PATCH 25/42] [CNContact] fix updateFriend method --- Classes/Utils/FastAddressBook.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 774b33415..e17c4b69d 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -406,11 +406,11 @@ @try { NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:&saveError]); + [self updateFriend:contact]; } @catch (NSException *exception) { NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", [exception description]); - [self updateFriend:contact]; - return FALSE; + return FALSE; } [self reloadAllContacts]; return TRUE; From 9e2bd9dc264c71f2a40e94222483b0972097cf1e Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Fri, 17 Nov 2017 14:41:17 +0100 Subject: [PATCH 26/42] release: version 3.16.5 build 4 --- linphone-Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linphone-Info.plist b/linphone-Info.plist index 630b626a0..97d02c7df 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -53,7 +53,7 @@ CFBundleVersion - 3 + 4 ITSAppUsesNonExemptEncryption ITSEncryptionExportComplianceCode From 010d13b85836639bdd09974dbf7cdbb99d58065d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 17 Nov 2017 17:05:17 +0100 Subject: [PATCH 27/42] update linphone: fix silent call after conference call. --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index bd08e5940..fecdf406b 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit bd08e5940c7358a945fff0d0e47678440a1b4ba5 +Subproject commit fecdf406bb16c5c64b4acff89cc06a256bd0f471 From 78b691f3fc1f282cbd3ef29537f977a6156175cc Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Tue, 21 Nov 2017 10:31:47 +0100 Subject: [PATCH 28/42] [GSU] linphone/ms2/ortp submodules updated --- linphone-Info.plist | 2 +- submodules/linphone | 2 +- submodules/mediastreamer2 | 2 +- submodules/ortp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/linphone-Info.plist b/linphone-Info.plist index 97d02c7df..2fbf2b150 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -53,7 +53,7 @@ CFBundleVersion - 4 + 7 ITSAppUsesNonExemptEncryption ITSEncryptionExportComplianceCode diff --git a/submodules/linphone b/submodules/linphone index fecdf406b..bbf8b49e0 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit fecdf406bb16c5c64b4acff89cc06a256bd0f471 +Subproject commit bbf8b49e03b46a9ad6b1e7f32e6d48b0836aa6e3 diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 0876afaf5..05fda93c2 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0876afaf521161c83c20e64a1770ffe20359cbec +Subproject commit 05fda93c22f364f3e88b29138aefd73bc44087c9 diff --git a/submodules/ortp b/submodules/ortp index 5f8fcddce..3319a460d 160000 --- a/submodules/ortp +++ b/submodules/ortp @@ -1 +1 @@ -Subproject commit 5f8fcddce392f1510768949a4691f9e8c170badb +Subproject commit 3319a460d5f55b343899c091cb15c395a4f3fea4 From aa78cc74f5550a54fb6ebfc1972fcebee8b3049e Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Tue, 21 Nov 2017 11:46:14 +0100 Subject: [PATCH 29/42] [ORTP fix] fix compil error -> -DORTP logs --- linphone.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index f4e2c1c65..1a7b1e87f 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -4564,7 +4564,7 @@ HEADER_SEARCH_PATHS = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LIBRARY_SEARCH_PATHS = ""; - OTHER_CFLAGS = "-DORTP_LOG_DOMAIN=\\\"ios\\\""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PROVISIONING_PROFILE = "0636A6EA-90EB-4D92-B707-19FC32F9A7CF"; SDKROOT = iphoneos; @@ -4661,7 +4661,7 @@ HEADER_SEARCH_PATHS = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LIBRARY_SEARCH_PATHS = ""; - OTHER_CFLAGS = "-DORTP_LOG_DOMAIN=\\\"ios\\\""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; @@ -4758,7 +4758,7 @@ HEADER_SEARCH_PATHS = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LIBRARY_SEARCH_PATHS = ""; - OTHER_CFLAGS = "-DORTP_LOG_DOMAIN=\\\"ios\\\""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PROVISIONING_PROFILE = "C7F794BC-6D48-41F2-B37D-E1B1B1A40901"; SDKROOT = iphoneos; @@ -4857,7 +4857,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LIBRARY_SEARCH_PATHS = ""; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = "-DORTP_LOG_DOMAIN=\\\"ios\\\""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; PROVISIONING_PROFILE = "2AC0DC11-4546-47B6-8B8A-453CCA80903C"; SDKROOT = iphoneos; From f69c0f87f93db4fb0b5484ec5f4947de38c8183b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 Nov 2017 14:01:11 +0100 Subject: [PATCH 30/42] Fix exceptions "out of main thread" exceptions when changing some button's aspects upon audio route changes. --- Classes/CallOutgoingView.m | 4 +++- Classes/LinphoneUI/UISpeakerButton.m | 3 ++- linphone.xcodeproj/project.pbxproj | 4 ++++ submodules/linphone | 2 +- submodules/mediastreamer2 | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Classes/CallOutgoingView.m b/Classes/CallOutgoingView.m index e8afaa1dd..4d6d6958f 100644 --- a/Classes/CallOutgoingView.m +++ b/Classes/CallOutgoingView.m @@ -150,7 +150,9 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)bluetoothAvailabilityUpdateEvent:(NSNotification *)notif { bool available = [[notif.userInfo objectForKey:@"available"] intValue]; - [self hideSpeaker:available]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self hideSpeaker:available]; + }); } @end diff --git a/Classes/LinphoneUI/UISpeakerButton.m b/Classes/LinphoneUI/UISpeakerButton.m index b845885fe..54985014d 100644 --- a/Classes/LinphoneUI/UISpeakerButton.m +++ b/Classes/LinphoneUI/UISpeakerButton.m @@ -42,7 +42,8 @@ INIT_WITH_COMMON_CF { #pragma mark - UIToggleButtonDelegate Functions - (void)audioRouteChangeListenerCallback:(NSNotification *)notif { - [self update]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self update];}); } - (void)onOn { diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 1a7b1e87f..c0ef95cd5 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -4516,6 +4516,7 @@ LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -4613,6 +4614,7 @@ LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -4710,6 +4712,7 @@ LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -4807,6 +4810,7 @@ LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; diff --git a/submodules/linphone b/submodules/linphone index bbf8b49e0..d17635390 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit bbf8b49e03b46a9ad6b1e7f32e6d48b0836aa6e3 +Subproject commit d1763539033ef552a491c227e03df2e6af5ba607 diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 05fda93c2..f82450663 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 05fda93c22f364f3e88b29138aefd73bc44087c9 +Subproject commit f82450663f3d89aa6aa4dc4bae7d060b3a5be495 From c43cb8c72f7550c916dd6d595f007d8f4b8c012b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 Nov 2017 14:02:26 +0100 Subject: [PATCH 31/42] fix audio disapearance when entering in conferencing mode (callkit issue) --- Classes/ProviderDelegate.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/ProviderDelegate.m b/Classes/ProviderDelegate.m index 6178d2f85..276273131 100644 --- a/Classes/ProviderDelegate.m +++ b/Classes/ProviderDelegate.m @@ -209,11 +209,12 @@ LinphoneManager.instance.speakerBeforePause = LinphoneManager.instance.speakerEnabled; linphone_call_pause((LinphoneCall *)call); } else { - [self configAudioSession:[AVAudioSession sharedInstance]]; + if (linphone_core_get_conference(LC)) { linphone_core_enter_conference(LC); [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; } else { + [self configAudioSession:[AVAudioSession sharedInstance]]; self.pendingCall = call; } } From 6d32c03fea8ef0e8d5f740c7aacb0f0b9c3276db Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Tue, 21 Nov 2017 14:20:38 +0100 Subject: [PATCH 32/42] release: version 3.16.5 build 7 --- linphone-Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linphone-Info.plist b/linphone-Info.plist index 2fbf2b150..fec3a6130 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -53,7 +53,7 @@ CFBundleVersion - 7 + 8 ITSAppUsesNonExemptEncryption ITSEncryptionExportComplianceCode From bf0ae9a61e76f32c7f2d698f074bd0a0285cee51 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 23 Nov 2017 16:36:12 +0100 Subject: [PATCH 33/42] [GSU] submodule updated + methods linphone_friend_list_find_friend_by_uri change --- submodules/linphone | 2 +- submodules/mediastreamer2 | 2 +- submodules/ortp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/linphone b/submodules/linphone index d17635390..f4184738c 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit d1763539033ef552a491c227e03df2e6af5ba607 +Subproject commit f4184738c9c17d068408f196424f6638da8e6141 diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index f82450663..16ee1217a 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit f82450663f3d89aa6aa4dc4bae7d060b3a5be495 +Subproject commit 16ee1217a9725bcde21ee5cd375da769b0177e38 diff --git a/submodules/ortp b/submodules/ortp index 3319a460d..c6224a9fc 160000 --- a/submodules/ortp +++ b/submodules/ortp @@ -1 +1 @@ -Subproject commit 3319a460d5f55b343899c091cb15c395a4f3fea4 +Subproject commit c6224a9fc088ea998482fbf77111c9a3c76b00ae From dfc5af3c7f8c531a56e31d896ef3eca0cf254f25 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Thu, 23 Nov 2017 16:36:58 +0100 Subject: [PATCH 34/42] [CNContact] contact loading time optimised --- Classes/Contact.m | 110 ++++++++++++++------------------ Classes/ContactsListTableView.m | 19 ++++-- Classes/LinphoneManager.h | 11 +++- Classes/LinphoneManager.m | 19 +++++- Classes/PhoneMainView.h | 4 ++ Classes/PhoneMainView.m | 15 +++++ Classes/Utils/FastAddressBook.m | 53 ++++++++------- 7 files changed, 135 insertions(+), 96 deletions(-) diff --git a/Classes/Contact.m b/Classes/Contact.m index 8fde471f9..b377b2d54 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -29,74 +29,60 @@ _sipAddresses = [[NSMutableArray alloc] init]; _emails = [[NSMutableArray alloc] init]; if (_person) { - _identifier = _person.identifier; - _firstName = _person.givenName; - _lastName = _person.familyName; - _displayName = [NSString stringWithFormat:@"%@ %@", _firstName, _lastName]; - for (CNLabeledValue *phoneNumber in _person.phoneNumbers) { - [_phones addObject:phoneNumber.value.stringValue]; - } - if ([_person respondsToSelector:NSSelectorFromString( - CNInstantMessageAddressUsernameKey)] || - [_person respondsToSelector:NSSelectorFromString( - CNContactInstantMessageAddressesKey)]) { - if (_person.instantMessageAddresses != NULL) { - for (CNLabeledValue *sipAddr in _person - .instantMessageAddresses) { - [_sipAddresses addObject:sipAddr.value.username]; - } - } - } - for (CNLabeledValue *email in _person.emailAddresses) { - [_emails addObject:email.value]; - } - const char *key = - [NSString stringWithFormat:@"ab%@", acncontact.identifier].UTF8String; - // try to find friend associated with that person - _friend = linphone_friend_list_find_friend_by_ref_key( - linphone_core_get_default_friend_list(LC), key); - if (!_friend) { - _friend = linphone_friend_ref(linphone_core_create_friend(LC)); - linphone_friend_set_ref_key(_friend, key); - linphone_friend_set_name( - _friend, - [NSString - stringWithFormat:@"%@%@", _firstName ? _firstName : @"", - _lastName - ? [_firstName ? @" " : @"" - stringByAppendingString:_lastName] - : @""] - .UTF8String); - for (NSString *sipAddr in _sipAddresses) { - LinphoneAddress *addr = - linphone_core_interpret_url(LC, sipAddr.UTF8String); - if (addr) { - linphone_address_set_display_name(addr, - [self displayName].UTF8String); - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - } - } - for (NSString *phone in _phones) { - linphone_friend_add_phone_number(_friend, phone.UTF8String); - } - if (_friend) { - linphone_friend_enable_subscribes(_friend, FALSE); - linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny); - linphone_core_add_friend(LC, _friend); - } - } - linphone_friend_ref(_friend); + _identifier = _person.identifier; + _firstName = _person.givenName; + _lastName = _person.familyName; + _displayName = [NSString stringWithFormat:@"%@ %@", _firstName, _lastName]; + for (CNLabeledValue *phoneNumber in _person.phoneNumbers) { + [_phones addObject:phoneNumber.value.stringValue]; + } + if ([_person respondsToSelector:NSSelectorFromString( CNInstantMessageAddressUsernameKey)] || [_person respondsToSelector:NSSelectorFromString(CNContactInstantMessageAddressesKey)]) { + if (_person.instantMessageAddresses != NULL) { + for (CNLabeledValue *sipAddr in _person.instantMessageAddresses) { + [_sipAddresses addObject:sipAddr.value.username]; + } + } + } + for (CNLabeledValue *email in _person.emailAddresses) { + [_emails addObject:email.value]; + } + const char *key = [NSString stringWithFormat:@"ab%@", acncontact.identifier].UTF8String; + // try to find friend associated with that person + _friend = linphone_friend_list_find_friend_by_ref_key(linphone_core_get_default_friend_list(LC), key); + if (!_friend) { + _friend = linphone_friend_ref(linphone_core_create_friend(LC)); + linphone_friend_set_ref_key(_friend, key); + linphone_friend_set_name(_friend, [NSString stringWithFormat:@"%@%@", _firstName ? _firstName : @"", _lastName ? [_firstName ? @" " : @"" stringByAppendingString:_lastName] : @""] .UTF8String); + for (NSString *sipAddr in _sipAddresses) { + LinphoneAddress *addr = linphone_core_interpret_url(LC, sipAddr.UTF8String); + if (addr) { + linphone_address_set_display_name(addr, [self displayName].UTF8String); + linphone_friend_add_address(_friend, addr); + linphone_address_destroy(addr); + } + } + for (NSString *phone in _phones) { + linphone_friend_add_phone_number(_friend, phone.UTF8String); + } + if (_friend) { + linphone_friend_enable_subscribes(_friend, FALSE); + linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny); + linphone_core_add_friend(LC, _friend); + } + } + linphone_friend_ref(_friend); + } else if (_friend) { - [self loadFriend]; + [self loadFriend]; } else { - LOGE(@"Contact cannot be initialized"); - return nil; + LOGE(@"Contact cannot be initialized"); + return nil; } - LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", + /* LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", self.firstName ?: @"", self.lastName ?: @"", self.phones.count, self.sipAddresses.count, self.emails.count); + */ return self; } diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index 29a713e50..3eb1d684e 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -110,7 +110,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } - (NSString *)displayNameForContact:(Contact *)person { - NSString *name = [FastAddressBook displayNameForContact:person]; + NSString *name = person.displayName; if (name != nil && [name length] > 0 && ![name isEqualToString:NSLocalizedString(@"Unknown", nil)]) { // Add the contact only if it fuzzy match filter too (if any) if ([ContactSelection getNameOrEmailFilter] == nil || @@ -119,18 +119,22 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { // Sort contacts by first letter. We need to translate the name to ASCII first, because of UTF-8 // issues. For instance expected order would be: Alberta(A tilde) before ASylvano. - NSData *name2ASCIIdata = [name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + /* NSData *name2ASCIIdata = [name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; NSString *name2ASCII = [[NSString alloc] initWithData:name2ASCIIdata encoding:NSASCIIStringEncoding]; - return name2ASCII; + */ return name; } } return nil; } -// TODO - check this - (void)loadData { _ongoing = TRUE; LOGI(@"Load contact list"); + NSString* previous = [PhoneMainView.instance getPreviousViewName]; + addressBookMap = [LinphoneManager.instance getLinphoneManagerAddressBookMap]; + BOOL updated = [LinphoneManager.instance getContactsUpdated]; + if(([previous isEqualToString:@"ContactsDetailsView"] && updated)|| [addressBookMap count] == 0){ + [LinphoneManager.instance setContactsUpdated:FALSE]; @synchronized(addressBookMap) { //Set all contacts from ContactCell to nil for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j) @@ -224,6 +228,8 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } }); } + [LinphoneManager.instance setLinphoneManagerAddressBookMap:addressBookMap]; + } _ongoing = FALSE; } @@ -433,7 +439,10 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { selector:@selector(onAddressBookUpdate:) name:kLinphoneAddressBookUpdate object:nil]; - [self loadData]; + dispatch_async(dispatch_get_main_queue(), + ^{ + [self loadData]; + }); } } diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index adba17596..1ee25a20c 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -33,7 +33,7 @@ #include "linphone/linphonecore.h" #include "bctoolbox/list.h" - +#import "OrderedDictionary.h" #import "ProviderDelegate.h" extern NSString *const LINPHONERC_APPLICATION_KEY; @@ -197,6 +197,13 @@ typedef struct _LinphoneManagerSounds { - (void)shouldPresentLinkPopup; - (void)setProviderDelegate:(ProviderDelegate *)del; + +- (void) setLinphoneManagerAddressBookMap:(OrderedDictionary*) addressBook; +- (OrderedDictionary*) getLinphoneManagerAddressBookMap; + +- (void) setContactsUpdated:(BOOL) updated; +- (BOOL) getContactsUpdated; + @property ProviderDelegate *providerDelegate; @property (readonly) BOOL isTesting; @@ -225,5 +232,7 @@ typedef struct _LinphoneManagerSounds { @property BOOL nextCallIsTransfer; @property BOOL conf; @property NSDictionary *pushDict; +@property(strong, nonatomic) OrderedDictionary *linphoneManagerAddressBookMap; +@property (nonatomic, assign) BOOL contactsUpdated; @end diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 5aa090def..a1fb3e75e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -257,7 +257,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre _bluetoothEnabled = FALSE; _conf = FALSE; _fileTransferDelegates = [[NSMutableArray alloc] init]; - + _linphoneManagerAddressBookMap = [[OrderedDictionary alloc] init]; pushCallIDs = [[NSMutableArray alloc] init]; _photoLibrary = [[ALAssetsLibrary alloc] init]; _isTesting = [LinphoneManager isRunningTests]; @@ -292,6 +292,23 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre [NSNotificationCenter.defaultCenter removeObserver:self]; } +#pragma mark - AddressBookMap + +- (void) setLinphoneManagerAddressBookMap:(OrderedDictionary*) addressBook{ + _linphoneManagerAddressBookMap = addressBook; +} + +- (OrderedDictionary*) getLinphoneManagerAddressBookMap{ + return _linphoneManagerAddressBookMap; +} + +- (void) setContactsUpdated:(BOOL) updated{ + _contactsUpdated = updated; +} +- (BOOL) getContactsUpdated{ + return _contactsUpdated; +} + #pragma deploymate push "ignored-api-availability" - (void)silentPushFailed:(NSTimer *)timer { if (_silentPushCompletion) { diff --git a/Classes/PhoneMainView.h b/Classes/PhoneMainView.h index 0ccf21b9b..3ac43c52a 100644 --- a/Classes/PhoneMainView.h +++ b/Classes/PhoneMainView.h @@ -79,6 +79,7 @@ @property(nonatomic, strong) IBOutlet UICompositeView *mainViewController; @property(nonatomic, strong) NSString *currentName; +@property(nonatomic, strong) NSString *previousView; @property(nonatomic, strong) NSString *name; @property(weak, readonly) UICompositeViewDescription *currentView; @property LinphoneChatRoom* currentRoom; @@ -87,6 +88,9 @@ - (void)changeCurrentView:(UICompositeViewDescription *)view; - (UIViewController*)popCurrentView; - (UIViewController *)popToView:(UICompositeViewDescription *)currentView; +- (void) setPreviousViewName:(NSString*)previous; +- (NSString*) getPreviousViewName; ++ (NSString*) getPreviousViewName; - (UICompositeViewDescription *)firstView; - (void)hideStatusBar:(BOOL)hide; - (void)hideTabBar:(BOOL)hide; diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 8f2f694f2..7a54ed38a 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -128,6 +128,7 @@ static RootViewManager *rootViewManagerInstance = nil; currentView = nil; _currentRoom = NULL; _currentName = NULL; + _previousView = nil; inhibitedEvents = [[NSMutableArray alloc] init]; } @@ -657,6 +658,7 @@ static RootViewManager *rootViewManagerInstance = nil; PhoneMainView *vc = [[RootViewManager instance] setViewControllerForDescription:view]; if (![view equal:vc.currentView] || vc != self) { LOGI(@"Change current view to %@", view.name); + [self setPreviousViewName:vc.currentView.name]; NSMutableArray *viewStack = [RootViewManager instance].viewDescriptionStack; [viewStack addObject:view]; if (animated && transition == nil) @@ -683,6 +685,19 @@ static RootViewManager *rootViewManagerInstance = nil; return [self _changeCurrentView:view transition:[PhoneMainView getBackwardTransition] animated:ANIMATED]; } +- (void) setPreviousViewName:(NSString*)previous{ + _previousView = previous; +} + +- (NSString*) getPreviousViewName { + return _previousView; +} + ++ (NSString*) getPreviousViewName { + return [self getPreviousViewName]; +} + + - (UICompositeViewDescription *)firstView { UICompositeViewDescription *view = nil; NSArray *viewStack = [RootViewManager instance].viewDescriptionStack; diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index e17c4b69d..291663573 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -91,8 +91,7 @@ + (NSString *)normalizeSipURI:(NSString *)address { // replace all whitespaces (non-breakable, utf8 nbsp etc.) by the "classical" whitespace - NSString *normalizedSipAddress = [[address - componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@" "]; + NSString *normalizedSipAddress = nil; LinphoneAddress *addr = linphone_core_interpret_url(LC, [address UTF8String]); if (addr != NULL) { linphone_address_clean(addr); @@ -100,8 +99,11 @@ normalizedSipAddress = [NSString stringWithUTF8String:tmp]; ms_free(tmp); linphone_address_destroy(addr); + return normalizedSipAddress; + }else { + normalizedSipAddress = [[address componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@" "]; + return normalizedSipAddress; } - return normalizedSipAddress; } + (BOOL)isAuthorized { @@ -112,8 +114,10 @@ if ((self = [super init]) != nil) { store = [[CNContactStore alloc] init]; _addressBookMap = [NSMutableDictionary dictionary]; - [self reloadAllContacts]; - } + dispatch_async(dispatch_get_main_queue(), ^{ + [self reloadAllContacts]; + }); + } self.needToUpdate = FALSE; if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_9_x_Max) { @@ -167,13 +171,14 @@ error:&contactError]; NSArray *keysToFetch = @[ CNContactEmailAddressesKey, CNContactPhoneNumbersKey, - CNContactFamilyNameKey, CNContactGivenNameKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey, CNContactPostalAddressesKey, CNContactIdentifierKey, CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey, CNInstantMessageAddressUsernameKey, CNContactImageDataKey ]; CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; + success = [store enumerateContactsWithFetchRequest:request error:&contactError @@ -183,10 +188,10 @@ NSLog(@"error fetching contacts %@", contactError); } else { - Contact *newContact = [[Contact alloc] + Contact *newContact = [[Contact alloc] initWithCNContact:contact]; [self registerAddrsFor:newContact]; - } + } }]; // load Linphone friends const MSList *lists = linphone_core_get_friends_lists(LC); @@ -214,25 +219,18 @@ } - (void)registerAddrsFor:(Contact *)contact { - for (NSString *phone in contact.phones) { - char *normalizedPhone = linphone_proxy_config_normalize_phone_number( - linphone_core_get_default_proxy_config(LC), phone.UTF8String); - NSString *name = [FastAddressBook - normalizeSipURI:normalizedPhone - ? [NSString stringWithUTF8String:normalizedPhone] - : phone]; - if (phone != NULL) { - [_addressBookMap - setObject:contact - forKey:(name ?: [FastAddressBook localizedLabel:phone])]; - } - if (normalizedPhone) - ms_free(normalizedPhone); - } - for (NSString *sip in contact.sipAddresses) { - [_addressBookMap setObject:contact - forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; - } + for (NSString *phone in contact.phones) { + char *normalizedPhone = linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); + NSString *name = [FastAddressBook normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : phone]; + if (phone != NULL) { + [_addressBookMap setObject:contact forKey:(name ?: [FastAddressBook localizedLabel:phone])]; + } + if (normalizedPhone) + ms_free(normalizedPhone); + } + for (NSString *sip in contact.sipAddresses) { + [_addressBookMap setObject:contact forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; + } } #pragma mark - Tools @@ -407,6 +405,7 @@ NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:&saveError]); [self updateFriend:contact]; + [LinphoneManager.instance setContactsUpdated:TRUE]; } @catch (NSException *exception) { NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", [exception description]); From 9db5a8e0724bca041ccecdf8bd69ed98d6222046 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Fri, 24 Nov 2017 16:13:07 +0100 Subject: [PATCH 35/42] [CNContact] update loading contact bckgrd thread --- Classes/Utils/FastAddressBook.m | 132 +++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 44 deletions(-) diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 291663573..8a302140f 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -112,44 +112,79 @@ - (FastAddressBook *)init { if ((self = [super init]) != nil) { - store = [[CNContactStore alloc] init]; - _addressBookMap = [NSMutableDictionary dictionary]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self reloadAllContacts]; - }); + store = [[CNContactStore alloc] init]; + _addressBookMap = [NSMutableDictionary dictionary]; } - self.needToUpdate = FALSE; - if (floor(NSFoundationVersionNumber) >= - NSFoundationVersionNumber_iOS_9_x_Max) { - if ([CNContactStore class]) { - // ios9 or later - if (store == NULL) - store = [[CNContactStore alloc] init]; - CNEntityType entityType = CNEntityTypeContacts; - if ([CNContactStore authorizationStatusForEntityType:entityType] == - CNAuthorizationStatusNotDetermined) { - LOGD(@"CNContactStore requesting authorization"); - [store requestAccessForEntityType:entityType - completionHandler:^(BOOL granted, - NSError *_Nullable error) { - LOGD(@"CNContactStore authorization granted"); - }]; - } else if ([CNContactStore - authorizationStatusForEntityType:entityType] == - CNAuthorizationStatusAuthorized) { - LOGD(@"CNContactStore authorization granted"); - } - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(updateAddressBook:) - name:CNContactStoreDidChangeNotification - object:nil]; - //[self reload]; - store = [[CNContactStore alloc] init]; - [self reloadAllContacts]; - } - } - return self; + self.needToUpdate = FALSE; + if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_9_x_Max) { + if ([CNContactStore class]) { + // ios9 or later + if (store == NULL) + store = [[CNContactStore alloc] init]; + [self fetchContactsInBackGroundThread]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil]; + } + } + return self; +} + +- (void) fetchContactsInBackGroundThread{ + + CNEntityType entityType = CNEntityTypeContacts; + [store requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError *_Nullable error) { + BOOL success = FALSE; + if(granted){ + LOGD(@"CNContactStore authorization granted"); + + NSError *contactError; + CNContactStore* store = [[CNContactStore alloc] init]; + [store containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers:@[ store.defaultContainerIdentifier]] error:&contactError]; + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey, + CNContactPostalAddressesKey, CNContactIdentifierKey, + CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey, + CNInstantMessageAddressUsernameKey, CNContactImageDataKey + ]; + CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; + + success = [store enumerateContactsWithFetchRequest:request error:&contactError usingBlock:^(CNContact *__nonnull contact, BOOL *__nonnull stop) { + if (contactError) { + NSLog(@"error fetching contacts %@", + contactError); + } else { + + dispatch_async(dispatch_get_main_queue(), ^{ + Contact *newContact = [[Contact alloc] initWithCNContact:contact]; + [self registerAddrsFor:newContact]; + }); + + } + }]; + } + + }]; + // load Linphone friends + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + LinphoneFriendList *fl = lists->data; + const MSList *friends = linphone_friend_list_get_friends(fl); + while (friends) { + LinphoneFriend *f = friends->data; + // only append friends that are not native contacts (already added + // above) + if (linphone_friend_get_ref_key(f) == NULL) { + Contact *contact = [[Contact alloc] initWithFriend:f]; + [self registerAddrsFor:contact]; + } + friends = friends->next; + } + linphone_friend_list_update_subscriptions(fl); + lists = lists->next; + } + [NSNotificationCenter.defaultCenter + postNotificationName:kLinphoneAddressBookUpdate + object:self]; } -(void) updateAddressBook:(NSNotification*) notif { @@ -163,6 +198,7 @@ [_addressBookMap removeAllObjects]; // iOS 9 or later NSError *contactError; + CNContactStore* store = [[CNContactStore alloc] init]; [store containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers:@[ @@ -219,17 +255,26 @@ } - (void)registerAddrsFor:(Contact *)contact { - for (NSString *phone in contact.phones) { + Contact* mContact = contact; + for (NSString *phone in mContact.phones) { char *normalizedPhone = linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); NSString *name = [FastAddressBook normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : phone]; if (phone != NULL) { - [_addressBookMap setObject:contact forKey:(name ?: [FastAddressBook localizedLabel:phone])]; + if(_addressBookMap){ + if(mContact){ + [_addressBookMap setObject:mContact forKey:(name ?: [FastAddressBook localizedLabel:phone])]; + }else{ + // Dosomte + } + + } + } if (normalizedPhone) ms_free(normalizedPhone); } - for (NSString *sip in contact.sipAddresses) { - [_addressBookMap setObject:contact forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; + for (NSString *sip in mContact.sipAddresses) { + [_addressBookMap setObject:mContact forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; } } @@ -333,12 +378,11 @@ [saveRequest deleteContact:[contact mutableCopy]]; @try { NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); - [self reloadAllContacts]; + [self fetchContactsInBackGroundThread]; } @catch (NSException *exception) { NSLog(@"description = %@", [exception description]); return FALSE; } - [self reloadAllContacts]; return TRUE; } @@ -411,7 +455,7 @@ [exception description]); return FALSE; } - [self reloadAllContacts]; + [self fetchContactsInBackGroundThread]; return TRUE; } From 03034bc316b864c5c7af376c81b641757b61e121 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 25 Nov 2017 16:38:06 +0100 Subject: [PATCH 36/42] update submodules (fixes ICE issue) --- submodules/bctoolbox | 2 +- submodules/linphone | 2 +- submodules/ortp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/bctoolbox b/submodules/bctoolbox index 02caea7df..ebc8b893e 160000 --- a/submodules/bctoolbox +++ b/submodules/bctoolbox @@ -1 +1 @@ -Subproject commit 02caea7df8381b0c5dadcfbfd39ff0b33a2577b7 +Subproject commit ebc8b893e4aab92ff6ee49674d7c443045494a6c diff --git a/submodules/linphone b/submodules/linphone index f4184738c..2b3d4ae3c 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit f4184738c9c17d068408f196424f6638da8e6141 +Subproject commit 2b3d4ae3cfaf82e286fe16d8ae0bac57d7abf1a7 diff --git a/submodules/ortp b/submodules/ortp index c6224a9fc..4cea5e6e7 160000 --- a/submodules/ortp +++ b/submodules/ortp @@ -1 +1 @@ -Subproject commit c6224a9fc088ea998482fbf77111c9a3c76b00ae +Subproject commit 4cea5e6e7b6da329030b4f34b66a6168b864bb1d From 4bdf3f78f5ddec619418b1f5ad19056167ac1198 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Mon, 27 Nov 2017 12:10:38 +0100 Subject: [PATCH 37/42] [Contacts] fix sip filtered list in contactListView --- Classes/ContactsListTableView.m | 6 +++--- Classes/ContactsListView.m | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index 3eb1d684e..294443400 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -119,9 +119,9 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { // Sort contacts by first letter. We need to translate the name to ASCII first, because of UTF-8 // issues. For instance expected order would be: Alberta(A tilde) before ASylvano. - /* NSData *name2ASCIIdata = [name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + NSData *name2ASCIIdata = [name dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; NSString *name2ASCII = [[NSString alloc] initWithData:name2ASCIIdata encoding:NSASCIIStringEncoding]; - */ return name; + return name2ASCII; } } return nil; @@ -133,7 +133,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { NSString* previous = [PhoneMainView.instance getPreviousViewName]; addressBookMap = [LinphoneManager.instance getLinphoneManagerAddressBookMap]; BOOL updated = [LinphoneManager.instance getContactsUpdated]; - if(([previous isEqualToString:@"ContactsDetailsView"] && updated)|| [addressBookMap count] == 0){ + if(([previous isEqualToString:@"ContactsDetailsView"] && updated) || updated || [addressBookMap count] == 0){ [LinphoneManager.instance setContactsUpdated:FALSE]; @synchronized(addressBookMap) { //Set all contacts from ContactCell to nil diff --git a/Classes/ContactsListView.m b/Classes/ContactsListView.m index a102d74b9..3a988b632 100644 --- a/Classes/ContactsListView.m +++ b/Classes/ContactsListView.m @@ -165,6 +165,7 @@ static UICompositeViewDescription *compositeDescription = nil; linphoneButton.selected = FALSE; [tableController loadData]; } else if (view == ContactsLinphone && !linphoneButton.selected) { + [LinphoneManager.instance setContactsUpdated:TRUE]; frame.origin.x = linphoneButton.frame.origin.x; [ContactSelection setSipFilter:LinphoneManager.instance.contactFilter]; [ContactSelection enableEmailFilter:FALSE]; From f1e6e0c2701fb8c5d40c3966f02f41e9e318631e Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Mon, 27 Nov 2017 14:52:30 +0100 Subject: [PATCH 38/42] [Clean-up] Code clean-up + speed-up --- Classes/AssistantLinkView.m | 8 +- Classes/AssistantView.m | 21 ++-- Classes/LinphoneAppDelegate.m | 4 +- Classes/LinphoneCoreSettingsStore.m | 2 +- Classes/LinphoneManager.m | 2 +- Classes/LinphoneUI/UIContactDetailsCell.m | 1 - Classes/Utils/FastAddressBook.h | 3 +- Classes/Utils/FastAddressBook.m | 131 ++++++---------------- TestsUI/LinphoneTestCase.m | 11 +- 9 files changed, 56 insertions(+), 127 deletions(-) diff --git a/Classes/AssistantLinkView.m b/Classes/AssistantLinkView.m index 1b0bad163..06a1d7082 100644 --- a/Classes/AssistantLinkView.m +++ b/Classes/AssistantLinkView.m @@ -199,10 +199,10 @@ void assistant_activate_phone_number_link(LinphoneAccountCreator *creator, Linph } [PhoneMainView.instance popToView:DialerView.compositeViewDescription]; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneAddressBookUpdate object:NULL]; - [LinphoneManager.instance.fastAddressBook reloadAllContacts]; - } else { - [thiz showErrorPopup:resp]; - } + [LinphoneManager.instance.fastAddressBook fetchContactsInBackGroundThread]; + } else { + [thiz showErrorPopup:resp]; + } } #pragma mark - other diff --git a/Classes/AssistantView.m b/Classes/AssistantView.m index 7048d0d39..823c86255 100644 --- a/Classes/AssistantView.m +++ b/Classes/AssistantView.m @@ -412,7 +412,7 @@ static UICompositeViewDescription *compositeDescription = nil; linphone_core_set_default_proxy_config(LC, new_config); // reload address book to prepend proxy config domain to contacts' phone number // todo: STOP doing that! - [[LinphoneManager.instance fastAddressBook] reloadAllContacts]; + [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread]; } else { [self displayAssistantConfigurationError]; } @@ -1369,17 +1369,14 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun linphone_core_set_default_proxy_config(LC, config); // reload address book to prepend proxy config domain to contacts' phone number // todo: STOP doing that! - [[LinphoneManager.instance fastAddressBook] - reloadAllContacts]; - [PhoneMainView.instance - changeCurrentView: - DialerView.compositeViewDescription]; - } else { - [self displayAssistantConfigurationError]; - } - } else { - [self displayAssistantConfigurationError]; - } + [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread]; + [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; + } else { + [self displayAssistantConfigurationError]; + } + } else { + [self displayAssistantConfigurationError]; + } }); } diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 4e56fbac1..7f0d024a0 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -91,7 +91,7 @@ if (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription || PhoneMainView.instance.currentView == ContactDetailsView.compositeViewDescription) { [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; } - [instance.fastAddressBook reloadAllContacts]; + [instance.fastAddressBook fetchContactsInBackGroundThread]; instance.fastAddressBook.needToUpdate = FALSE; const MSList *lists = linphone_core_get_friends_lists(LC); while (lists) { @@ -968,7 +968,7 @@ didInvalidatePushTokenForType:(NSString *)type { linphone_core_set_provisioning_uri(LC, [configURL UTF8String]); [LinphoneManager.instance destroyLinphoneCore]; [LinphoneManager.instance startLinphoneCore]; - [LinphoneManager.instance.fastAddressBook reloadAllContacts]; + [LinphoneManager.instance.fastAddressBook fetchContactsInBackGroundThread]; } #pragma mark - Prevent ImagePickerView from rotating diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index c0d7e4d75..3d4659bc6 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -636,7 +636,7 @@ } } // reload address book to prepend proxy config domain to contacts' phone number - [[LinphoneManager.instance fastAddressBook] reloadAllContacts]; + [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread]; } - (void)synchronizeCodecs:(const MSList *)codecs { diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index a1fb3e75e..04559532c 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2181,7 +2181,7 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat [self destroyLinphoneCore]; [self createLinphoneCore]; // reload friends - [self.fastAddressBook reloadAllContacts]; + [self.fastAddressBook fetchContactsInBackGroundThread]; // reset network state to trigger a new network connectivity assessment linphone_core_set_network_reachable(theLinphoneCore, FALSE); diff --git a/Classes/LinphoneUI/UIContactDetailsCell.m b/Classes/LinphoneUI/UIContactDetailsCell.m index 76326c098..39b25a77d 100644 --- a/Classes/LinphoneUI/UIContactDetailsCell.m +++ b/Classes/LinphoneUI/UIContactDetailsCell.m @@ -128,7 +128,6 @@ - (IBAction)onCallClick:(id)event { LinphoneAddress *addr = [LinphoneUtils normalizeSipOrPhoneAddress:_addressLabel.text]; - LOGE(@"=====>>>> onCallClick() : %@ ", [NSString stringWithUTF8String:linphone_address_as_string(addr)] ); [LinphoneManager.instance call:addr]; if (addr) linphone_address_destroy(addr); diff --git a/Classes/Utils/FastAddressBook.h b/Classes/Utils/FastAddressBook.h index 606cf1576..2c7224830 100644 --- a/Classes/Utils/FastAddressBook.h +++ b/Classes/Utils/FastAddressBook.h @@ -28,8 +28,7 @@ @property(readonly, nonatomic) NSMutableDictionary *addressBookMap; @property BOOL needToUpdate; -- (BOOL)reloadAllContacts; -//- (void)saveAddressBook; +- (void) fetchContactsInBackGroundThread; - (BOOL)deleteContact:(Contact *)contact; - (BOOL)deleteCNContact:(CNContact *)CNContact; - (BOOL)deleteAllContacts; diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index 8a302140f..23a47cb51 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -192,68 +192,6 @@ self.needToUpdate = TRUE; } -- (BOOL)reloadAllContacts { - BOOL success = FALSE; - if ([CNContactStore class]) { - [_addressBookMap removeAllObjects]; - // iOS 9 or later - NSError *contactError; - CNContactStore* store = [[CNContactStore alloc] init]; - [store - containersMatchingPredicate:[CNContainer - predicateForContainersWithIdentifiers:@[ - store.defaultContainerIdentifier - ]] - error:&contactError]; - NSArray *keysToFetch = @[ - CNContactEmailAddressesKey, CNContactPhoneNumbersKey, - CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey, - CNContactPostalAddressesKey, CNContactIdentifierKey, - CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey, - CNInstantMessageAddressUsernameKey, CNContactImageDataKey - ]; - CNContactFetchRequest *request = - [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; - - success = - [store enumerateContactsWithFetchRequest:request - error:&contactError - usingBlock:^(CNContact *__nonnull contact, - BOOL *__nonnull stop) { - if (contactError) { - NSLog(@"error fetching contacts %@", - contactError); - } else { - Contact *newContact = [[Contact alloc] - initWithCNContact:contact]; - [self registerAddrsFor:newContact]; - } - }]; - // load Linphone friends - const MSList *lists = linphone_core_get_friends_lists(LC); - while (lists) { - LinphoneFriendList *fl = lists->data; - const MSList *friends = linphone_friend_list_get_friends(fl); - while (friends) { - LinphoneFriend *f = friends->data; - // only append friends that are not native contacts (already added - // above) - if (linphone_friend_get_ref_key(f) == NULL) { - Contact *contact = [[Contact alloc] initWithFriend:f]; - [self registerAddrsFor:contact]; - } - friends = friends->next; - } - linphone_friend_list_update_subscriptions(fl); - lists = lists->next; - } - } - [NSNotificationCenter.defaultCenter - postNotificationName:kLinphoneAddressBookUpdate - object:self]; - return success; -} - - (void)registerAddrsFor:(Contact *)contact { Contact* mContact = contact; for (NSString *phone in mContact.phones) { @@ -374,44 +312,45 @@ } - (BOOL)deleteCNContact:(CNContact *)contact { - CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; - [saveRequest deleteContact:[contact mutableCopy]]; - @try { - NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); - [self fetchContactsInBackGroundThread]; - } @catch (NSException *exception) { - NSLog(@"description = %@", [exception description]); - return FALSE; - } - return TRUE; + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + [saveRequest deleteContact:[contact mutableCopy]]; + @try { + BOOL success = [store executeSaveRequest:saveRequest error:nil]; + NSLog(@"Success %d", success); + if(success) + [self fetchContactsInBackGroundThread]; + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; + } + return TRUE; } - (BOOL)deleteAllContacts { NSArray *keys = @[ CNContactPhoneNumbersKey ]; NSString *containerId = store.defaultContainerIdentifier; - NSPredicate *predicate = - [CNContact predicateForContactsInContainerWithIdentifier:containerId]; + NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId]; NSError *error; NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys - error:&error]; - if (error) { - NSLog(@"error fetching contacts %@", error); - return FALSE; - } else { - CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; - for (CNContact *contact in cnContacts) { - [saveRequest deleteContact:[contact mutableCopy]]; - } - @try { - NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); - } @catch (NSException *exception) { - NSLog(@"description = %@", [exception description]); - return FALSE; - } + error:&error]; + if (error) { + NSLog(@"error fetching contacts %@", error); + return FALSE; + } else { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + for (CNContact *contact in cnContacts) { + [saveRequest deleteContact:[contact mutableCopy]]; + } + @try { + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; + } NSLog(@"Deleted contacts %lu", (unsigned long)cnContacts.count); - } - return TRUE; + } + return TRUE; } - (BOOL)saveContact:(Contact *)contact { @@ -446,14 +385,12 @@ } NSError *saveError; @try { - NSLog(@"Success %d", - [store executeSaveRequest:saveRequest error:&saveError]); - [self updateFriend:contact]; + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:&saveError]); + [self updateFriend:contact]; [LinphoneManager.instance setContactsUpdated:TRUE]; } @catch (NSException *exception) { - NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", - [exception description]); - return FALSE; + NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", [exception description]); + return FALSE; } [self fetchContactsInBackGroundThread]; return TRUE; diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index 8c82a871f..5ca6f0da5 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -150,14 +150,11 @@ linphone_core_set_file_transfer_server(lc, "https://www.linphone.org:444/lft.php"); // reload address book to prepend proxy config domain to contacts' phone number - [[[LinphoneManager instance] fastAddressBook] - reloadAllContacts]; + [[[LinphoneManager instance] fastAddressBook] fetchContactsInBackGroundThread]; - [self waitForRegistration]; - [[LinphoneManager instance] - lpConfigSetInt:NO - forKey:@"animations_preference"]; - } + [self waitForRegistration]; + [[LinphoneManager instance] lpConfigSetInt:NO forKey:@"animations_preference"]; + } } - (UITableView *)findTableView:(NSString *)table { From a2b245612e3f31ddf772656265d7cbc296c83280 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 29 Nov 2017 08:45:55 +0100 Subject: [PATCH 39/42] add codec2 setting --- Classes/LinphoneManager.m | 4 ++++ Settings/InAppSettings.bundle/Audio.plist | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 04559532c..8d15d0a13 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -83,6 +83,7 @@ extern void libmsx264_init(MSFactory *factory); extern void libmsopenh264_init(MSFactory *factory); extern void libmssilk_init(MSFactory *factory); extern void libmswebrtc_init(MSFactory *factory); +extern void libmscodec2_init(MSFactory *factory); #define FRONT_CAM_NAME \ "AV Capture: com.apple.avfoundation.avcapturedevice.built-in_video:1" /*"AV Capture: Front Camera"*/ @@ -141,6 +142,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre {"mpeg4-generic", 48000, "aaceld_48k_preference"}, {"opus", 48000, "opus_preference"}, {"BV16", 8000, "bv16_preference"}, + {"CODEC2", 8000, "codec2_preference"}, {NULL, 0, Nil}}; + (NSString *)getPreferenceForCodec:(const char *)name withRate:(int)rate { @@ -2112,6 +2114,8 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat libmsx264_init(f); libmsopenh264_init(f); libmswebrtc_init(f); + libmscodec2_init(f); + linphone_core_reload_ms_plugins(theLinphoneCore, NULL); [self migrationAllPost]; diff --git a/Settings/InAppSettings.bundle/Audio.plist b/Settings/InAppSettings.bundle/Audio.plist index e9abc8db7..6a2b70e36 100644 --- a/Settings/InAppSettings.bundle/Audio.plist +++ b/Settings/InAppSettings.bundle/Audio.plist @@ -202,6 +202,16 @@ Type PSToggleSwitchSpecifier + + Key + codec2_preference + Title + codec2 + Type + PSToggleSwitchSpecifier + DefaultValue + + Key audio_advanced_group From d4da217ce5e9b747a8e1a56245c25638a695b867 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Wed, 29 Nov 2017 11:15:17 +0100 Subject: [PATCH 40/42] [Release] v.16.5 build 10 --- CHANGELOG.md | 15 +++ Classes/ContactsListTableView.m | 162 ++++++++++++++------------------ Classes/ContactsListView.m | 1 + linphone-Info.plist | 2 +- 4 files changed, 87 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e55ecb0..da549f8e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,21 @@ Group changes to describe their impact on the project, as follows: Fixed for any bug fixes. Security to invite users to upgrade in case of vulnerabilities. +## [3.16.5] - 2017-11-28 + +### Added +- Support of IOS 11 + +### Changed +- Contact, CNContact implmentation. +- Contacts loading optimization. +- Sound management updated + +### Fixed +- Chat file resend fixed +- Minor bugs fixes +- Audio fixed on conference call + ## [3.16.3] - 2017-05-03 ### Added diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index 294443400..a9c8b55b4 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -134,103 +134,81 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { addressBookMap = [LinphoneManager.instance getLinphoneManagerAddressBookMap]; BOOL updated = [LinphoneManager.instance getContactsUpdated]; if(([previous isEqualToString:@"ContactsDetailsView"] && updated) || updated || [addressBookMap count] == 0){ - [LinphoneManager.instance setContactsUpdated:FALSE]; - @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) + [LinphoneManager.instance setContactsUpdated:FALSE]; + @synchronized(addressBookMap) { + //Set all contacts from ContactCell to nil + for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j) { - [[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]] setContact:nil]; + 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]; + for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { + Contact *contact = nil; + @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { + contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; + } + BOOL add = true; + // Do not add the contact directly if we set some filter + if ([ContactSelection getSipFilter] || + [ContactSelection emailFilterEnabled]) { + add = false; + }else if ([FastAddressBook contactHasValidSipDomain:contact]) { + add = true; + }else if (contact.friend && + linphone_presence_model_get_basic_status( + linphone_friend_get_presence_model( + contact.friend)) == + LinphonePresenceBasicStatusOpen) { + add = true; + } + + if (!add && [ContactSelection emailFilterEnabled]) { + // Add this contact if it has an email + add = (contact.emails.count > 0); + } + + NSMutableString *name = [self displayNameForContact:contact] ? [[NSMutableString alloc] initWithString: [self displayNameForContact:contact]] : nil; + if (add && name != nil) { + NSString *firstChar = [[name substringToIndex:1] uppercaseString]; + // Put in correct subAr + if ([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') { + firstChar = @"#"; + } + NSMutableArray *subAr = [addressBookMap objectForKey:firstChar]; + if (subAr == nil) { + subAr = [[NSMutableArray alloc] init]; + [addressBookMap insertObject:subAr forKey:firstChar selector:@selector(caseInsensitiveCompare:)]; + } + NSUInteger idx = [subAr indexOfObject:contact inSortedRange:(NSRange){0, subAr.count} options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult( Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2] options:NSCaseInsensitiveSearch]; + }]; + if (![subAr containsObject:contact]) { + [subAr insertObject:contact atIndex:idx]; + } + } + //} + } + [super loadData]; + + // since we refresh the tableview, we must perform this on main + // thread + dispatch_async(dispatch_get_main_queue(), ^(void) { + if (IPAD) { + if (!([self totalNumberOfItems] > 0)) { + ContactDetailsView *view = VIEW(ContactDetailsView); + [view setContact:nil]; + } + } + }); } - - // Reset Address book - [addressBookMap removeAllObjects]; - for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { - @synchronized( - LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = - [LinphoneManager.instance.fastAddressBook.addressBookMap - objectForKey:addr]; - BOOL add = true; - // Do not add the contact directly if we set some filter - if ([ContactSelection getSipFilter] || - [ContactSelection emailFilterEnabled]) { - add = false; - } - if ([FastAddressBook contactHasValidSipDomain:contact]) { - add = true; - } - if (contact.friend && - linphone_presence_model_get_basic_status( - linphone_friend_get_presence_model( - contact.friend)) == - LinphonePresenceBasicStatusOpen) { - add = true; - } - - if (!add && [ContactSelection emailFilterEnabled]) { - // Add this contact if it has an email - add = (contact.emails.count > 0); - } - - NSMutableString *name = - [self displayNameForContact:contact] - ? [[NSMutableString alloc] - initWithString: - [self displayNameForContact:contact]] - : nil; - if (add && name != nil) { - NSString *firstChar = - [[name substringToIndex:1] uppercaseString]; - - // Put in correct subAr - if ([firstChar characterAtIndex:0] < 'A' || - [firstChar characterAtIndex:0] > 'Z') { - firstChar = @"#"; - } - NSMutableArray *subAr = - [addressBookMap objectForKey:firstChar]; - if (subAr == nil) { - subAr = [[NSMutableArray alloc] init]; - [addressBookMap - insertObject:subAr - forKey:firstChar - selector:@selector(caseInsensitiveCompare:)]; - } - NSUInteger idx = [subAr - indexOfObject:contact - inSortedRange:(NSRange){0, subAr.count} - options:NSBinarySearchingInsertionIndex - usingComparator:^NSComparisonResult( - Contact *_Nonnull obj1, Contact *_Nonnull obj2) { - return [[self displayNameForContact:obj1] - compare:[self displayNameForContact:obj2] - options:NSCaseInsensitiveSearch]; - }]; - if (![subAr containsObject:contact]) { - [subAr insertObject:contact atIndex:idx]; - } - } - } - } - [super loadData]; - - // since we refresh the tableview, we must perform this on main - // thread - dispatch_async(dispatch_get_main_queue(), ^(void) { - if (IPAD) { - if (!([self totalNumberOfItems] > 0)) { - ContactDetailsView *view = VIEW(ContactDetailsView); - [view setContact:nil]; - } - } - }); - } [LinphoneManager.instance setLinphoneManagerAddressBookMap:addressBookMap]; } - _ongoing = FALSE; + _ongoing = FALSE; } - (void)loadSearchedData { diff --git a/Classes/ContactsListView.m b/Classes/ContactsListView.m index 3a988b632..ea3c5b52b 100644 --- a/Classes/ContactsListView.m +++ b/Classes/ContactsListView.m @@ -158,6 +158,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)changeView:(ContactsCategory)view { CGRect frame = _selectedButtonImage.frame; if (view == ContactsAll && !allButton.selected) { + [LinphoneManager.instance setContactsUpdated:TRUE]; frame.origin.x = allButton.frame.origin.x; [ContactSelection setSipFilter:nil]; [ContactSelection enableEmailFilter:FALSE]; diff --git a/linphone-Info.plist b/linphone-Info.plist index fec3a6130..53b0d6bde 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -53,7 +53,7 @@ CFBundleVersion - 8 + 9 ITSAppUsesNonExemptEncryption ITSEncryptionExportComplianceCode From e64e7153918943287763454c6cf21bb045094b6b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 30 Nov 2017 10:30:06 +0100 Subject: [PATCH 41/42] update linphone and ms2 to fix ICE issue --- submodules/linphone | 2 +- submodules/mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/linphone b/submodules/linphone index 2b3d4ae3c..d388532b5 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 2b3d4ae3cfaf82e286fe16d8ae0bac57d7abf1a7 +Subproject commit d388532b5a4c15f87764302614486e8b82c3c797 diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 16ee1217a..c7b8e6f14 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 16ee1217a9725bcde21ee5cd375da769b0177e38 +Subproject commit c7b8e6f14c9078bf0b1b3f3c197aa46c30de9075 From bc94e466232f036322836725cb6ee4fe814791a4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 30 Nov 2017 13:24:58 +0100 Subject: [PATCH 42/42] update linphone & mediastreamer2 --- submodules/linphone | 2 +- submodules/mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/linphone b/submodules/linphone index d388532b5..20efb4ad4 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit d388532b5a4c15f87764302614486e8b82c3c797 +Subproject commit 20efb4ad41357daf700fa393dbcae9fdb3ab2730 diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index c7b8e6f14..3f94be991 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit c7b8e6f14c9078bf0b1b3f3c197aa46c30de9075 +Subproject commit 3f94be991d4d7cf1f2e869e457c1a95eb9d518a5