Merge pull request #329 from RyanRory/fix-callkit

Fixed an issue where calls are not working on locked screen
pull/1053/head
Morgan Pretty 4 months ago committed by GitHub
commit 1ace299235
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -7778,7 +7778,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 496;
CURRENT_PROJECT_VERSION = 505;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7816,7 +7816,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.8.2;
MARKETING_VERSION = 2.8.3;
OTHER_LDFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
@ -7849,7 +7849,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 496;
CURRENT_PROJECT_VERSION = 505;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7887,7 +7887,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.8.2;
MARKETING_VERSION = 2.8.3;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
PRODUCT_NAME = Session;

@ -113,7 +113,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
// Construct a CXCallUpdate describing the incoming call, including the caller.
let update = CXCallUpdate()
update.localizedCallerName = callerName
update.remoteHandle = CXHandle(type: .generic, value: call.callId.uuidString)
update.remoteHandle = CXHandle(type: .generic, value: call.sessionId)
update.hasVideo = false
disableUnsupportedFeatures(callUpdate: update)
@ -140,11 +140,12 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
}
func handleCallEnded() {
SNLog("[Calls] Call ended.")
WebRTCSession.current = nil
UserDefaults.sharedLokiProject?[.isCallOngoing] = false
UserDefaults.sharedLokiProject?[.lastCallPreOffer] = nil
if Singleton.hasAppContext && Singleton.appContext.isInBackground {
if Singleton.hasAppContext && Singleton.appContext.isNotInForeground {
(UIApplication.shared.delegate as? AppDelegate)?.stopPollers()
Log.flush()
}
@ -198,6 +199,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
}
public static func suspendDatabaseIfCallEndedInBackground() {
SNLog("[Calls] suspendDatabaseIfCallEndedInBackground.")
if Singleton.hasAppContext && Singleton.appContext.isInBackground {
// FIXME: Initialise the `SessionCallManager` with a dependencies instance
let dependencies: Dependencies = Dependencies()
@ -238,8 +240,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
{
let callVC = CallVC(for: call)
callVC.conversationVC = conversationVC
conversationVC.inputAccessoryView?.isHidden = true
conversationVC.inputAccessoryView?.alpha = 0
conversationVC.hideInputAccessoryView()
presentingVC.present(callVC, animated: true, completion: nil)
}
else if !Preferences.isCallKitSupported {

@ -600,8 +600,11 @@ final class CallVC: UIViewController, VideoPreviewDelegate {
}
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { [weak self] _ in
self?.conversationVC?.showInputAccessoryView()
self?.presentingViewController?.dismiss(animated: true, completion: nil)
DispatchQueue.main.async {
self?.dismiss(animated: true, completion: {
self?.conversationVC?.showInputAccessoryView()
})
}
}
}
@ -623,9 +626,13 @@ final class CallVC: UIViewController, VideoPreviewDelegate {
AppEnvironment.shared.callManager.reportCurrentCallEnded(reason: nil)
}
DispatchQueue.main.async {
self?.conversationVC?.showInputAccessoryView()
self?.presentingViewController?.dismiss(animated: true, completion: nil)
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in
DispatchQueue.main.async {
self?.dismiss(animated: true, completion: {
self?.conversationVC?.becomeFirstResponder()
self?.conversationVC?.showInputAccessoryView()
})
}
}
}
}

@ -791,13 +791,23 @@ extension ConversationVC:
}
func hideInputAccessoryView() {
DispatchQueue.main.async {
self.inputAccessoryView?.isHidden = true
self.inputAccessoryView?.alpha = 0
guard Thread.isMainThread else {
DispatchQueue.main.async {
self.hideInputAccessoryView()
}
return
}
self.inputAccessoryView?.isHidden = true
self.inputAccessoryView?.alpha = 0
}
func showInputAccessoryView() {
guard Thread.isMainThread else {
DispatchQueue.main.async {
self.showInputAccessoryView()
}
return
}
UIView.animate(withDuration: 0.25, animations: {
self.inputAccessoryView?.isHidden = false
self.inputAccessoryView?.alpha = 1

@ -353,7 +353,7 @@ final class HomeVC: BaseVC, LibSessionRespondingViewController, UITableViewDataS
)
// Start polling if needed (i.e. if the user just created or restored their Session ID)
if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate {
if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate, !Singleton.appContext.isNotInForeground {
appDelegate.startPollersIfNeeded()
}

@ -985,6 +985,88 @@ SOFTWARE.
<key>License</key>
<string>The MIT License (MIT)
Copyright (c) 2016 swiftlyfalling (https://github.com/swiftlyfalling)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</string>
<key>Title</key>
<string>session-grdb-swift</string>
</dict>
<dict>
<key>License</key>
<string>The author disclaims copyright to this source code. In place of
a legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
</string>
<key>Title</key>
<string>session-grdb-swift</string>
</dict>
<dict>
<key>License</key>
<string>/*
** LICENSE for the sqlite3 WebAssembly/JavaScript APIs.
**
** This bundle (typically released as sqlite3.js or sqlite3.mjs)
** is an amalgamation of JavaScript source code from two projects:
**
** 1) https://emscripten.org: the Emscripten "glue code" is covered by
** the terms of the MIT license and University of Illinois/NCSA
** Open Source License, as described at:
**
** https://emscripten.org/docs/introducing_emscripten/emscripten_license.html
**
** 2) https://sqlite.org: all code and documentation labeled as being
** from this source are released under the same terms as the sqlite3
** C library:
**
** 2022-10-16
**
** The author disclaims copyright to this source code. In place of a
** legal notice, here is a blessing:
**
** * May you do good and not evil.
** * May you find forgiveness for yourself and forgive others.
** * May you share freely, never taking more than you give.
*/
</string>
<key>Title</key>
<string>session-grdb-swift</string>
</dict>
<dict>
<key>License</key>
<string>The author disclaims copyright to this source code. In place of
a legal notice, here is a blessing:
May you do good and not evil.
May you find forgiveness for yourself and forgive others.
May you share freely, never taking more than you give.
</string>
<key>Title</key>
<string>session-grdb-swift</string>
</dict>
<dict>
<key>License</key>
<string>The MIT License (MIT)
Copyright (c) 2015 ibireme &lt;ibireme@gmail.com&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy

@ -284,7 +284,8 @@ public enum PushRegistrationError: Error {
guard
let uuid: String = payload["uuid"] as? String,
let caller: String = payload["caller"] as? String,
let timestampMs: Int64 = payload["timestamp"] as? Int64
let timestampMs: UInt64 = payload["timestamp"] as? UInt64,
TimestampUtils.isWithinOneMinute(timestampMs: timestampMs)
else {
SessionCallManager.reportFakeCall(info: "Missing payload data") // stringlint:ignore
return
@ -297,40 +298,33 @@ public enum PushRegistrationError: Error {
LibSession.resumeNetworkAccess()
let maybeCall: SessionCall? = Storage.shared.write { db in
let messageInfo: CallMessage.MessageInfo = CallMessage.MessageInfo(
state: (caller == getUserHexEncodedPublicKey(db) ?
.outgoing :
.incoming
)
)
let messageInfoString: String? = {
if let messageInfoData: Data = try? JSONEncoder().encode(messageInfo) {
return String(data: messageInfoData, encoding: .utf8)
} else {
return "callsIncoming"
.put(key: "name", value: caller)
.localized()
}
}()
let call: SessionCall = SessionCall(db, for: caller, uuid: uuid, mode: .answer)
let thread: SessionThread = try SessionThread
.fetchOrCreate(db, id: caller, variant: .contact, shouldBeVisible: nil)
let interaction: Interaction = try Interaction(
messageUuid: uuid,
threadId: thread.id,
threadVariant: thread.variant,
authorId: caller,
variant: .infoCall,
body: messageInfoString,
timestampMs: timestampMs
)
.withDisappearingMessagesConfiguration(db, threadVariant: thread.variant)
.inserted(db)
var call: SessionCall? = nil
call.callInteractionId = interaction.id
do {
call = SessionCall(
db,
for: caller,
uuid: uuid,
mode: .answer
)
let thread: SessionThread = try SessionThread
.fetchOrCreate(
db,
id: caller,
variant: .contact,
shouldBeVisible: nil
)
let interaction: Interaction? = try Interaction
.filter(Interaction.Columns.threadId == thread.id)
.filter(Interaction.Columns.messageUuid == uuid)
.fetchOne(db)
call?.callInteractionId = interaction?.id
} catch {
SNLog("[Calls] Failed to create call due to error: \(error)")
}
return call
}
@ -340,12 +334,16 @@ public enum PushRegistrationError: Error {
return
}
JobRunner.appDidBecomeActive()
// NOTE: Just start 1-1 poller so that it won't wait for polling group messages
(UIApplication.shared.delegate as? AppDelegate)?.startPollersIfNeeded(shouldStartGroupPollers: false)
call.reportIncomingCallIfNeeded { error in
if let error = error {
SNLog("[Calls] Failed to report incoming call to CallKit due to error: \(error)")
} else {
SNLog("[Calls] Succeeded to report incoming call to CallKit")
}
}
}

@ -109,6 +109,7 @@ extension MessageReceiver {
// Ignore pre offer message after the same call instance has been generated
if let currentCall: CurrentCallProtocol = callManager.currentCall, currentCall.uuid == message.uuid {
SNLog("[MessageReceiver+Calls] Ignoring pre-offer message for call[\(currentCall.uuid)] instance because it is already active.")
return
}

@ -117,7 +117,7 @@ extension MessageReceiver {
}
// Update the `didApproveMe` state of the sender
try updateContactApprovalStatusIfNeeded(
let shouldInsertControlMessage: Bool = try updateContactApprovalStatusIfNeeded(
db,
senderSessionId: senderId,
threadId: nil
@ -138,6 +138,7 @@ extension MessageReceiver {
)
}
guard shouldInsertControlMessage else { return }
// Notify the user of their approval (Note: This will always appear in the un-blinded thread)
//
// Note: We want to do this last as it'll mean the un-blinded thread gets updated and the
@ -156,11 +157,11 @@ extension MessageReceiver {
).inserted(db)
}
internal static func updateContactApprovalStatusIfNeeded(
@discardableResult internal static func updateContactApprovalStatusIfNeeded(
_ db: Database,
senderSessionId: String,
threadId: String?
) throws {
) throws -> Bool {
let userPublicKey: String = getUserHexEncodedPublicKey(db)
// If the sender of the message was the current user
@ -171,13 +172,13 @@ extension MessageReceiver {
let threadId: String = threadId,
let thread: SessionThread = try? SessionThread.fetchOne(db, id: threadId),
!thread.isNoteToSelf(db)
else { return }
else { return true }
// Sending a message to someone flags them as approved so create the contact record if
// it doesn't exist
let contact: Contact = Contact.fetchOrCreate(db, id: threadId)
guard !contact.isApproved else { return }
guard !contact.isApproved else { return false }
try? contact.save(db)
_ = try? Contact
@ -189,12 +190,14 @@ extension MessageReceiver {
// someone without approving them)
let contact: Contact = Contact.fetchOrCreate(db, id: senderSessionId)
guard !contact.didApproveMe else { return }
guard !contact.didApproveMe else { return false }
try? contact.save(db)
_ = try? Contact
.filter(id: senderSessionId)
.updateAllAndConfig(db, Contact.Columns.didApproveMe.set(to: true))
}
return true
}
}

@ -413,7 +413,9 @@ public class Poller {
job: job,
canStartJob: (
!forceSynchronousProcessing &&
(Singleton.hasAppContext && !Singleton.appContext.isInBackground)
(Singleton.hasAppContext && !Singleton.appContext.isInBackground) ||
// FIXME: Better seperate the call messages handling, since we need to handle them all the time
SessionEnvironment.shared?.callManager.wrappedValue?.currentCall != nil
),
using: dependencies
)

@ -46,7 +46,9 @@ public extension AppContext {
var frontmostViewController: UIViewController? { nil }
var backgroundTimeRemaining: TimeInterval { 0 }
// Note: CallKit will make the app state as .inactive
var isInBackground: Bool { reportedApplicationState == .background }
var isNotInForeground: Bool { reportedApplicationState != .active }
var isAppForegroundAndActive: Bool { reportedApplicationState == .active }
// MARK: - Paths

Loading…
Cancel
Save