Skip to content

Commit

Permalink
Merge pull request #1915 from nextcloud/use-call-notification-state-api
Browse files Browse the repository at this point in the history
feat(push): Use call notification state api
  • Loading branch information
Ivansss authored Dec 16, 2024
2 parents bea8547 + ee483c9 commit bbd8b50
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 5 deletions.
53 changes: 48 additions & 5 deletions NextcloudTalk/CallKitManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ - (void)reportIncomingCall:(NSString *)token withDisplayName:(NSString *)display
[weakSelf.hangUpTimers setObject:hangUpTimer forKey:callUUID];

// Add callStateTimer to timers array
NSTimer *callStateTimer = [NSTimer scheduledTimerWithTimeInterval:kCallKitManagerCheckCallStateEverySeconds target:self selector:@selector(checkCallStateForCall:) userInfo:call repeats:NO];
NSTimer *callStateTimer = [NSTimer scheduledTimerWithTimeInterval:kCallKitManagerCheckCallStateEverySeconds target:self selector:@selector(checkCallStateForTimer:) userInfo:call repeats:NO];
[weakSelf.callStateTimers setObject:callStateTimer forKey:callUUID];

// Get call info from server
Expand Down Expand Up @@ -358,14 +358,57 @@ - (void)presentMissedCallNotificationForCall:(CallKitCall *)call
}
}

- (void)checkCallStateForCall:(NSTimer *)timer
- (void)checkCallStateForTimer:(NSTimer *)timer
{
CallKitCall *call = [timer userInfo];
if (!call) {
return;
}

if ([[NCDatabaseManager sharedInstance] serverHasTalkCapability:kCapabilityCallNotificationState forAccountId:call.accountId]) {
[self checkCallStateWithStateApiForCall:call];
} else {
[self checkCallStateWithPeersForCall:call];
}
}

- (void)checkCallStateWithStateApiForCall:(CallKitCall *)call
{
__weak CallKitManager *weakSelf = self;

TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:call.accountId];
[[NCAPIController sharedInstance] getCallNotificationStateFor:account forRoom:call.token completionBlock:^(enum CallNotificationState state) {
// Make sure call is still ringing at this point to avoid a race-condition between answering the call on this device and the API callback
if (!call.isRinging) {
return;
}

if (state == CallNotificationStateRoomNotFound) {
// The conversation was not found for this participant
// Mostlikely the conversation was removed while an incoming call was ongoing
[self endCallWithUUID:call.uuid];
return;
} else if (state == CallNotificationStateMissedCall) {
// No one is in the call, we can hang up and show missed call notification
[self presentMissedCallNotificationForCall:call];
[self endCallWithUUID:call.uuid];
return;
} else if (state == CallNotificationStateParticipantJoined) {
// Account is already in a call (answered the call on a different device) -> no need to keep ringing
[self endCallWithUUID:call.uuid];
return;
}

// Reschedule next check
NSTimer *callStateTimer = [NSTimer scheduledTimerWithTimeInterval:kCallKitManagerCheckCallStateEverySeconds target:self selector:@selector(checkCallStateForTimer:) userInfo:call repeats:NO];
[weakSelf.callStateTimers setObject:callStateTimer forKey:call.uuid];
}];
}

- (void)checkCallStateWithPeersForCall:(CallKitCall *)call
{
__weak CallKitManager *weakSelf = self;

TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:call.accountId];
[[NCAPIController sharedInstance] getPeersForCall:call.token forAccount:account withCompletionBlock:^(NSMutableArray *peers, NSError *error, NSInteger statusCode) {
// Make sure call is still ringing at this point to avoid a race-condition between answering the call on this device and the API callback
Expand All @@ -386,7 +429,7 @@ - (void)checkCallStateForCall:(NSTimer *)timer
[self endCallWithUUID:call.uuid];
return;
}

NSInteger callAPIVersion = [[NCAPIController sharedInstance] callAPIVersionForAccount:account];
for (NSMutableDictionary *user in peers) {
NSString *userId = [user objectForKey:@"userId"];
Expand All @@ -401,9 +444,9 @@ - (void)checkCallStateForCall:(NSTimer *)timer
return;
}
}

// Reschedule next check
NSTimer *callStateTimer = [NSTimer scheduledTimerWithTimeInterval:kCallKitManagerCheckCallStateEverySeconds target:self selector:@selector(checkCallStateForCall:) userInfo:call repeats:NO];
NSTimer *callStateTimer = [NSTimer scheduledTimerWithTimeInterval:kCallKitManagerCheckCallStateEverySeconds target:self selector:@selector(checkCallStateForTimer:) userInfo:call repeats:NO];
[weakSelf.callStateTimers setObject:callStateTimer forKey:call.uuid];
}];
}
Expand Down
34 changes: 34 additions & 0 deletions NextcloudTalk/NCAPIControllerExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,40 @@ import Foundation
}
}

// MARK: - Notifications

// Needs to be of type Int to be usable from objc
@objc public enum CallNotificationState: Int {
case unknown, stillCurrent, roomNotFound, missedCall, participantJoined
}

@discardableResult
public func getCallNotificationState(for account: TalkAccount, forRoom roomToken: String, completionBlock: @escaping (_ callNotificationState: CallNotificationState) -> Void) -> URLSessionDataTask? {
guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
let encodedToken = roomToken.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
else {
completionBlock(.unknown)
return nil
}

let apiVersion = self.callAPIVersion(for: account)
let urlString = self.getRequestURL(forEndpoint: "call/\(encodedToken)/notification-state", withAPIVersion: apiVersion, for: account)

return apiSessionManager.getOcs(urlString, account: account) { ocsResponse, ocsError in
if ocsResponse?.responseStatusCode == 200 {
completionBlock(.stillCurrent)
} else if ocsResponse?.responseStatusCode == 201 {
completionBlock(.missedCall)
} else if ocsError?.responseStatusCode == 403 {
completionBlock(.roomNotFound)
} else if ocsError?.responseStatusCode == 404 {
completionBlock(.participantJoined)
} else {
completionBlock(.unknown)
}
}
}

// MARK: - Archived conversations

public func archiveRoom(_ token: String, forAccount account: TalkAccount, completionBlock: @escaping (_ success: Bool) -> Void) {
Expand Down
1 change: 1 addition & 0 deletions NextcloudTalk/NCDatabaseManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ extern NSString * const kCapabilityMentionPermissions;
extern NSString * const kCapabilityEditMessagesNoteToSelf;
extern NSString * const kCapabilityChatSummary;
extern NSString * const kCapabilityArchivedConversationsV2;
extern NSString * const kCapabilityCallNotificationState;

extern NSString * const kNotificationsCapabilityExists;
extern NSString * const kNotificationsCapabilityTestPush;
Expand Down
1 change: 1 addition & 0 deletions NextcloudTalk/NCDatabaseManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
NSString * const kCapabilityEditMessagesNoteToSelf = @"edit-messages-note-to-self";
NSString * const kCapabilityChatSummary = @"chat-summary-api";
NSString * const kCapabilityArchivedConversationsV2 = @"archived-conversations-v2";
NSString * const kCapabilityCallNotificationState = @"call-notification-state-api";

NSString * const kNotificationsCapabilityExists = @"exists";
NSString * const kNotificationsCapabilityTestPush = @"test-push";
Expand Down

0 comments on commit bbd8b50

Please sign in to comment.