presence: implement long term presence
|
|
@ -25,6 +25,39 @@
|
|||
|
||||
if (_person) {
|
||||
[self loadProperties];
|
||||
|
||||
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, _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) {
|
||||
LOGI(@"fixme! use linphone_friend_add_phone_number for phone numbers");
|
||||
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);
|
||||
}
|
||||
// linphone_friend_add_phone_number(_friend, phone.UTF8String);
|
||||
}
|
||||
linphone_core_add_friend(LC, _friend);
|
||||
}
|
||||
linphone_friend_ref(_friend);
|
||||
} else if (_friend) {
|
||||
[self loadFriend];
|
||||
} else {
|
||||
|
|
@ -59,6 +92,12 @@
|
|||
}
|
||||
|
||||
- (NSString *)displayName {
|
||||
if (_friend) {
|
||||
const char *dp = linphone_address_get_display_name(linphone_friend_get_address(_friend));
|
||||
if (dp)
|
||||
return [NSString stringWithUTF8String:dp];
|
||||
}
|
||||
|
||||
if (_person != nil) {
|
||||
NSString *lFirstName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty));
|
||||
NSString *lLocalizedFirstName = [FastAddressBook localizedLabel:lFirstName];
|
||||
|
|
@ -77,10 +116,6 @@
|
|||
} else {
|
||||
return (NSString *)lLocalizedOrganization;
|
||||
}
|
||||
} else if (_friend) {
|
||||
const char *dp = linphone_address_get_display_name(linphone_friend_get_address(_friend));
|
||||
if (dp)
|
||||
return [NSString stringWithUTF8String:dp];
|
||||
}
|
||||
|
||||
if (_lastName || _firstName) {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ extern NSString *const kLinphoneBluetoothAvailabilityUpdate;
|
|||
extern NSString *const kLinphoneConfiguringStateUpdate;
|
||||
extern NSString *const kLinphoneGlobalStateUpdate;
|
||||
extern NSString *const kLinphoneNotifyReceived;
|
||||
extern NSString *const kLinphoneNotifyPresenceReceived;
|
||||
extern NSString *const kLinphoneCallEncryptionChanged;
|
||||
extern NSString *const kLinphoneFileTransferSendUpdate;
|
||||
extern NSString *const kLinphoneFileTransferRecvUpdate;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ NSString *const kLinphoneBluetoothAvailabilityUpdate = @"LinphoneBluetoothAvaila
|
|||
NSString *const kLinphoneConfiguringStateUpdate = @"LinphoneConfiguringStateUpdate";
|
||||
NSString *const kLinphoneGlobalStateUpdate = @"LinphoneGlobalStateUpdate";
|
||||
NSString *const kLinphoneNotifyReceived = @"LinphoneNotifyReceived";
|
||||
NSString *const kLinphoneNotifyPresenceReceived = @"LinphoneNotifyPresenceReceived";
|
||||
NSString *const kLinphoneCallEncryptionChanged = @"LinphoneCallEncryptionChanged";
|
||||
NSString *const kLinphoneFileTransferSendUpdate = @"LinphoneFileTransferSendUpdate";
|
||||
NSString *const kLinphoneFileTransferRecvUpdate = @"LinphoneFileTransferRecvUpdate";
|
||||
|
|
@ -1041,6 +1042,17 @@ static void linphone_iphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev
|
|||
content:body];
|
||||
}
|
||||
|
||||
- (void)onNotifyPresenceReceived:(LinphoneCore *)lc friend:(LinphoneFriend *)lf {
|
||||
// Post event
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
[dict setObject:[NSValue valueWithPointer:lf] forKey:@"friend"];
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneNotifyPresenceReceived object:self userInfo:dict];
|
||||
}
|
||||
|
||||
static void linphone_iphone_notify_presence_received(LinphoneCore *lc, LinphoneFriend *lf) {
|
||||
[(__bridge LinphoneManager *)linphone_core_get_user_data(lc) onNotifyPresenceReceived:lc friend:lf];
|
||||
}
|
||||
|
||||
static void linphone_iphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on,
|
||||
const char *authentication_token) {
|
||||
[(__bridge LinphoneManager *)linphone_core_get_user_data(lc) onCallEncryptionChanged:lc
|
||||
|
|
@ -1326,7 +1338,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
|
|||
static LinphoneCoreVTable linphonec_vtable = {
|
||||
.call_state_changed = (LinphoneCoreCallStateChangedCb)linphone_iphone_call_state,
|
||||
.registration_state_changed = linphone_iphone_registration_state,
|
||||
.notify_presence_received = NULL,
|
||||
.notify_presence_received = linphone_iphone_notify_presence_received,
|
||||
.new_subscription_requested = NULL,
|
||||
.auth_info_requested = linphone_iphone_popup_password_request,
|
||||
.message_received = linphone_iphone_message_received,
|
||||
|
|
@ -1420,6 +1432,8 @@ static LinphoneCoreVTable linphonec_vtable = {
|
|||
linphone_core_enable_video_capture(theLinphoneCore, FALSE);
|
||||
}
|
||||
|
||||
[self enableProxyPublish:YES];
|
||||
|
||||
LOGI(@"Linphone [%s] started on [%s]", linphone_core_get_version(), [[UIDevice currentDevice].model UTF8String]);
|
||||
|
||||
// Post event
|
||||
|
|
@ -1666,10 +1680,42 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
LOGI(@"Long running task started, remaining [%g s] because at least one call is paused",
|
||||
[[UIApplication sharedApplication] backgroundTimeRemaining]);
|
||||
}
|
||||
|
||||
- (void)enableProxyPublish:(BOOL)enabled {
|
||||
if (linphone_core_get_global_state(LC) != LinphoneGlobalOn || !linphone_core_get_default_friend_list(LC)) {
|
||||
LOGW(@"Not changing presence configuration because linphone core not ready yet");
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self lpConfigBoolForKey:@"publish_presence"]) {
|
||||
// set present to "tv", because "available" does not work yet
|
||||
if (enabled) {
|
||||
linphone_core_set_presence_model(
|
||||
LC, linphone_core_create_presence_model_with_activity(LC, LinphonePresenceActivityTV, NULL));
|
||||
}
|
||||
|
||||
const MSList *proxies = linphone_core_get_proxy_config_list(LC);
|
||||
while (proxies) {
|
||||
LinphoneProxyConfig *cfg = proxies->data;
|
||||
linphone_proxy_config_edit(cfg);
|
||||
linphone_proxy_config_enable_publish(cfg, enabled);
|
||||
linphone_proxy_config_done(cfg);
|
||||
proxies = proxies->next;
|
||||
}
|
||||
// force registration update first, then update friend list subscription
|
||||
linphone_core_iterate(theLinphoneCore);
|
||||
}
|
||||
|
||||
linphone_friend_list_enable_subscriptions(linphone_core_get_default_friend_list(LC), enabled);
|
||||
}
|
||||
|
||||
- (BOOL)enterBackgroundMode {
|
||||
LinphoneProxyConfig *proxyCfg = linphone_core_get_default_proxy_config(theLinphoneCore);
|
||||
BOOL shouldEnterBgMode = FALSE;
|
||||
|
||||
// disable presence
|
||||
[self enableProxyPublish:NO];
|
||||
|
||||
// handle proxy config if any
|
||||
if (proxyCfg) {
|
||||
const char *refkey = proxyCfg ? linphone_proxy_config_get_ref_key(proxyCfg) : NULL;
|
||||
|
|
@ -1724,7 +1770,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
LOGI(@"Entering [%s] bg mode", shouldEnterBgMode ? "normal" : "lite");
|
||||
|
||||
if (!shouldEnterBgMode) {
|
||||
const char *refkey = linphone_proxy_config_get_ref_key(proxyCfg);
|
||||
const char *refkey = proxyCfg ? linphone_proxy_config_get_ref_key(proxyCfg) : NULL;
|
||||
BOOL pushNotifEnabled = (refkey && strcmp(refkey, "push_notification") == 0);
|
||||
if (pushNotifEnabled) {
|
||||
LOGI(@"Keeping lc core to handle push");
|
||||
|
|
@ -1740,6 +1786,8 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
}
|
||||
|
||||
- (void)becomeActive {
|
||||
// enable presence
|
||||
|
||||
[self refreshRegisters];
|
||||
if (pausedCallBgTask) {
|
||||
[[UIApplication sharedApplication] endBackgroundTask:pausedCallBgTask];
|
||||
|
|
@ -1765,6 +1813,8 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
LOGW(@"keepalive handler was called for the last time at %@", datestr);
|
||||
}
|
||||
}
|
||||
|
||||
[self enableProxyPublish:YES];
|
||||
}
|
||||
|
||||
- (void)beginInterruption {
|
||||
|
|
|
|||
14
Classes/LinphoneUI/UIAvatarPresence.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// UIAvatarPresence.h
|
||||
// linphone
|
||||
//
|
||||
// Created by Gautier Pelloux-Prayer on 12/04/16.
|
||||
//
|
||||
//
|
||||
|
||||
@interface UIAvatarPresence : UIRoundedImageView
|
||||
|
||||
@property(nonatomic, setter=setFriend:) LinphoneFriend *friend;
|
||||
@property(nonatomic, readonly) UIImageView *presenceImage;
|
||||
|
||||
@end
|
||||
85
Classes/LinphoneUI/UIAvatarPresence.m
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// UIAvatarPresence.m
|
||||
// linphone
|
||||
//
|
||||
// Created by Gautier Pelloux-Prayer on 12/04/16.
|
||||
//
|
||||
//
|
||||
|
||||
#import "UIAvatarPresence.h"
|
||||
|
||||
@implementation UIAvatarPresence
|
||||
|
||||
INIT_WITH_COMMON_CF {
|
||||
[NSNotificationCenter.defaultCenter addObserver:self
|
||||
selector:@selector(onPresenceChanged:)
|
||||
name:kLinphoneNotifyPresenceReceived
|
||||
object:nil];
|
||||
|
||||
if (!_presenceImage) {
|
||||
_presenceImage = [[UIImageView alloc] init];
|
||||
_presenceImage.tag = 883;
|
||||
[self addSubview:_presenceImage];
|
||||
}
|
||||
CGSize s = self.frame.size;
|
||||
int is = MIN(s.width, s.height);
|
||||
// place it in bottom right corner
|
||||
_presenceImage.frame = CGRectMake(.5 * (s.width - is) + .7 * is, .5 * (s.height - is) + .7 * is, .2 * is, .2 * is);
|
||||
|
||||
_presenceImage.image = [UIImage imageNamed:@"presence_unregistered"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
};
|
||||
- (void)setFrame:(CGRect)frame {
|
||||
[super setFrame:frame];
|
||||
|
||||
CGSize s = self.frame.size;
|
||||
int is = MIN(s.width, s.height);
|
||||
// place it in bottom right corner
|
||||
_presenceImage.frame = CGRectMake(.5 * (s.width - is) + .7 * is, .5 * (s.height - is) + .7 * is, .2 * is, .2 * is);
|
||||
}
|
||||
|
||||
- (void)onPresenceChanged:(NSNotification *)k {
|
||||
LinphoneFriend *f = [[k.userInfo valueForKey:@"friend"] pointerValue];
|
||||
// only consider event if it's about us
|
||||
if (!_friend ||
|
||||
!linphone_address_weak_equal(linphone_friend_get_address(f), linphone_friend_get_address(_friend))) {
|
||||
return;
|
||||
}
|
||||
[self updatePresenceImage];
|
||||
}
|
||||
|
||||
- (void)updatePresenceImage {
|
||||
LinphonePresenceBasicStatus basic =
|
||||
_friend ? linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(_friend))
|
||||
: LinphonePresenceBasicStatusClosed;
|
||||
const LinphonePresenceModel *model = _friend ? linphone_friend_get_presence_model(_friend) : NULL;
|
||||
LinphonePresenceActivity *activity =
|
||||
model ? linphone_presence_model_get_activity(model) ?: LinphonePresenceActivityOffline : NULL;
|
||||
|
||||
LOGE(@"Friend %s status is now %s/%s since %@", _friend ? linphone_friend_get_name(_friend) : "NULL",
|
||||
basic == LinphonePresenceBasicStatusOpen ? "open" : "closed", linphone_presence_activity_to_string(activity),
|
||||
[NSDate dateWithTimeIntervalSince1970:linphone_presence_model_get_timestamp(model)]);
|
||||
|
||||
NSString *imageName;
|
||||
if (basic == LinphonePresenceBasicStatusClosed) {
|
||||
imageName =
|
||||
(_friend && linphone_friend_is_presence_received(_friend)) ? @"presence_away" : @"presence_unregistered";
|
||||
} else if (linphone_presence_activity_get_type(activity) == LinphonePresenceActivityTV) {
|
||||
imageName = @"presence_online";
|
||||
} else {
|
||||
imageName = @"presence_away";
|
||||
}
|
||||
_presenceImage.image = [UIImage imageNamed:imageName];
|
||||
}
|
||||
|
||||
- (void)setFriend:(LinphoneFriend *) friend {
|
||||
_friend = friend;
|
||||
[self updatePresenceImage];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
- (void)setContact:(Contact *)acontact {
|
||||
_contact = acontact;
|
||||
[ContactDisplay setDisplayNameLabel:_nameLabel forContact:_contact];
|
||||
_linphoneImage.hidden = !([FastAddressBook contactHasValidSipDomain:_contact]);
|
||||
_linphoneImage.hidden = ! (_contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(_contact.friend)) == LinphonePresenceBasicStatusOpen);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
|||
|
|
@ -170,8 +170,11 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info
|
|||
const MSList *friends = linphone_friend_list_get_friends(fl);
|
||||
while (friends) {
|
||||
LinphoneFriend *f = friends->data;
|
||||
Contact *contact = [[Contact alloc] initWithFriend:f];
|
||||
[self registerAddrsFor:contact];
|
||||
// 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;
|
||||
}
|
||||
lists = lists->next;
|
||||
|
|
|
|||
|
|
@ -445,6 +445,9 @@
|
|||
else if ([machine isEqual:@"iPod7,1"])
|
||||
return @"iPod touch 6G";
|
||||
|
||||
else if ([machine isEqual:@"x86_64"])
|
||||
return @"simulator 64bits";
|
||||
|
||||
// none matched: cf https://www.theiphonewiki.com/wiki/Models for the whole list
|
||||
LOGW(@"%s: Oops, unknown machine %@... consider completing me!", __FUNCTION__, machine);
|
||||
return machine;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@
|
|||
<entry name="realm" overwrite="true"></entry>
|
||||
</section>
|
||||
|
||||
|
||||
<section name="sip">
|
||||
<entry name="rls_uri" overwrite="true"></entry>
|
||||
<entry name="use_rls_presence" overwrite="true"></entry>
|
||||
</section>
|
||||
|
||||
<section name="assistant">
|
||||
<entry name="domain" overwrite="true"></entry>
|
||||
<entry name="password_max_length" overwrite="true">-1</entry>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@
|
|||
<entry name="realm" overwrite="true">sip.linphone.org</entry>
|
||||
</section>
|
||||
|
||||
<section name="sip">
|
||||
<entry name="rls_uri" overwrite="true">sip:rls@sip.linphone.org</entry>
|
||||
<entry name="use_rls_presence" overwrite="true">1</entry>
|
||||
</section>
|
||||
|
||||
<section name="assistant">
|
||||
<entry name="domain" overwrite="true">sip.linphone.org</entry>
|
||||
<entry name="password_max_length" overwrite="true">-1</entry>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@
|
|||
<entry name="realm" overwrite="true">sip.linphone.org</entry>
|
||||
</section>
|
||||
|
||||
<section name="sip">
|
||||
<entry name="rls_uri" overwrite="true">sip:rls@sip.linphone.org</entry>
|
||||
<entry name="use_rls_presence" overwrite="true">1</entry>
|
||||
</section>
|
||||
|
||||
<section name="assistant">
|
||||
<entry name="domain" overwrite="true">sip.linphone.org</entry>
|
||||
<entry name="password_max_length" overwrite="true">34</entry>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@
|
|||
<entry name="realm" overwrite="true"></entry>
|
||||
</section>
|
||||
|
||||
|
||||
<section name="sip">
|
||||
<entry name="rls_uri" overwrite="true"></entry>
|
||||
<entry name="use_rls_presence" overwrite="true"></entry>
|
||||
</section>
|
||||
|
||||
<section name="assistant">
|
||||
<entry name="domain" overwrite="true"></entry>
|
||||
<entry name="password_max_length" overwrite="true">-1</entry>
|
||||
|
|
|
|||
BIN
Resources/images/presence_away.png
Normal file
|
After Width: | Height: | Size: 574 B |
BIN
Resources/images/presence_away@2x.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
Resources/images/presence_offline.png
Normal file
|
After Width: | Height: | Size: 230 B |
BIN
Resources/images/presence_offline@2x.png
Normal file
|
After Width: | Height: | Size: 376 B |
BIN
Resources/images/presence_online.png
Normal file
|
After Width: | Height: | Size: 617 B |
BIN
Resources/images/presence_online@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Resources/images/presence_unregistered.png
Normal file
|
After Width: | Height: | Size: 310 B |
BIN
Resources/images/presence_unregistered@2x.png
Normal file
|
After Width: | Height: | Size: 520 B |
|
|
@ -5,6 +5,7 @@
|
|||
debug_popup_email=linphone-iphone@belledonne-communications.com
|
||||
send_logs_include_linphonerc_and_chathistory=0
|
||||
#use_phone_number=0
|
||||
publish_presence=0
|
||||
|
||||
[assistant]
|
||||
password_length=-1
|
||||
|
|
@ -17,6 +18,7 @@ history_max_size=-1
|
|||
[sip]
|
||||
sip_random_port=0
|
||||
store_ha1_passwd=0
|
||||
handle_content_encoding=none
|
||||
|
||||
[sound]
|
||||
dtmf_player_amp=0.007
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 99b64aac55e58e885e89ed9265e6246cd16880a3
|
||||
Subproject commit aa0677fcc261a0adabe315593d452e1f65c9484c
|
||||