Show "Reconnecting..." on call screen

// FREEBIE
This commit is contained in:
Michael Kirk 2018-04-19 09:56:09 -04:00
parent 830ed884cf
commit 0f46834e8d
6 changed files with 88 additions and 8 deletions

View File

@ -676,6 +676,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
}
}
return formattedDate
case .reconnecting:
return NSLocalizedString("IN_CALL_RECONNECTING", comment: "Call setup status label")
case .remoteBusy:
return NSLocalizedString("END_CALL_RESPONDER_IS_BUSY", comment: "Call setup status label")
case .localFailure:
@ -694,18 +696,39 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
}
}
var isBlinkingReconnectLabel = false
func updateCallStatusLabel(callState: CallState) {
assert(Thread.isMainThread)
let text = String(format: CallStrings.callStatusFormat,
localizedTextForCallState(callState))
self.callStatusLabel.text = text
// Handle reconnecting blinking
if case .reconnecting = callState {
if !isBlinkingReconnectLabel {
isBlinkingReconnectLabel = true
UIView.animate(withDuration: 0.7, delay: 0, options: [.autoreverse, .repeat],
animations: {
self.callStatusLabel.alpha = 0.2
}, completion: nil)
} else {
// already blinking
}
} else {
// We're no longer in a reconnecting state, either the call failed or we reconnected.
// Stop the blinking animation
if isBlinkingReconnectLabel {
self.callStatusLabel.layer.removeAllAnimations()
self.callStatusLabel.alpha = 1
isBlinkingReconnectLabel = false
}
}
}
func updateCallUI(callState: CallState) {
assert(Thread.isMainThread)
updateCallStatusLabel(callState: callState)
if isShowingSettingsNag {
settingsNagView.isHidden = false
contactAvatarView.isHidden = true

View File

@ -289,6 +289,7 @@ protocol CallAudioServiceDelegate: class {
case .remoteRinging: handleRemoteRinging(call: call)
case .localRinging: handleLocalRinging(call: call)
case .connected: handleConnected(call: call)
case .reconnecting: handleReconnecting(call: call)
case .localFailure: handleLocalFailure(call: call)
case .localHangup: handleLocalHangup(call: call)
case .remoteHangup: handleRemoteHangup(call: call)
@ -335,6 +336,11 @@ protocol CallAudioServiceDelegate: class {
SwiftAssertIsOnMainThread(#function)
}
private func handleReconnecting(call: SignalCall) {
Logger.debug("\(self.logTag) \(#function)")
SwiftAssertIsOnMainThread(#function)
}
private func handleLocalFailure(call: SignalCall) {
Logger.debug("\(self.logTag) \(#function)")
SwiftAssertIsOnMainThread(#function)

View File

@ -547,7 +547,7 @@ protocol CallServiceObserver: class {
// If both users are trying to call each other at the same time,
// both should see busy.
handleRemoteBusy(thread: existingCall.thread, callId: existingCall.signalingId)
case .answering, .localRinging, .connected, .localFailure, .localHangup, .remoteHangup, .remoteBusy:
case .answering, .localRinging, .connected, .localFailure, .localHangup, .remoteHangup, .remoteBusy, .reconnecting:
// If one user calls another while the other has a "vestigial" call with
// that same user, fail the old call.
terminateCall()
@ -769,8 +769,31 @@ protocol CallServiceObserver: class {
Logger.info("\(self.logTag) call already ringing. Ignoring \(#function): \(call.identifiersForLogs).")
case .connected:
Logger.info("\(self.logTag) Call reconnected \(#function): \(call.identifiersForLogs).")
case .reconnecting:
call.state = .connected
case .idle, .localRinging, .localFailure, .localHangup, .remoteHangup, .remoteBusy:
owsFail("\(self.logTag) unexpected call state for \(#function): \(call.state): \(call.identifiersForLogs).")
}
}
private func handleIceDisconnected() {
SwiftAssertIsOnMainThread(#function)
guard let call = self.call else {
// This will only be called for the current peerConnectionClient, so
// fail the current call.
OWSProdError(OWSAnalyticsEvents.callServiceCallMissing(), file: #file, function: #function, line: #line)
handleFailedCurrentCall(error: CallError.assertionError(description: "\(self.logTag) ignoring \(#function) since there is no current call."))
return
}
Logger.info("\(self.logTag) in \(#function): \(call.identifiersForLogs).")
switch call.state {
case .connected:
call.state = .reconnecting
default:
Logger.debug("\(self.logTag) unexpected call state for \(#function): \(call.state): \(call.identifiersForLogs).")
owsFail("\(self.logTag) unexpected call state for \(#function): \(call.state): \(call.identifiersForLogs).")
}
}
@ -804,7 +827,7 @@ protocol CallServiceObserver: class {
switch call.state {
case .idle, .dialing, .answering, .localRinging, .localFailure, .remoteBusy, .remoteRinging:
handleMissedCall(call)
case .connected, .localHangup, .remoteHangup:
case .connected, .reconnecting, .localHangup, .remoteHangup:
Logger.info("\(self.logTag) call is finished.")
}
@ -1217,6 +1240,17 @@ protocol CallServiceObserver: class {
self.handleIceConnected()
}
func peerConnectionClientIceDisconnected(_ peerconnectionClient: PeerConnectionClient) {
SwiftAssertIsOnMainThread(#function)
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.logTag) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.handleIceDisconnected()
}
/**
* The connection failed to establish. The clients will not be able to communicate.
*/

View File

@ -27,6 +27,7 @@ protocol PeerConnectionClientDelegate: class {
/**
* The connection has been established. The clients can now communicate.
* This can be called multiple times throughout the call in the event of temporary network disconnects.
*/
func peerConnectionClientIceConnected(_ peerconnectionClient: PeerConnectionClient)
@ -35,6 +36,13 @@ protocol PeerConnectionClientDelegate: class {
*/
func peerConnectionClientIceFailed(_ peerconnectionClient: PeerConnectionClient)
/**
* After initially connecting, the connection disconnected.
* It maybe be temporary, in which case `peerConnectionClientIceConnected` will be called again once we're reconnected.
* Otherwise, `peerConnectionClientIceFailed` will eventually called.
*/
func peerConnectionClientIceDisconnected(_ peerconnectionClient: PeerConnectionClient)
/**
* During the Signaling process each client generates IceCandidates locally, which contain information about how to
* reach the local client via the internet. The delegate must shuttle these IceCandates to the other (remote) client
@ -676,6 +684,12 @@ class PeerConnectionClient: NSObject, RTCPeerConnectionDelegate, RTCDataChannelD
}
case .disconnected:
Logger.warn("\(self.TAG) RTCIceConnection disconnected.")
if let delegate = self.delegate {
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else { return }
delegate.peerConnectionClientIceDisconnected(strongSelf)
}
}
default:
Logger.debug("\(self.TAG) ignoring change IceConnectionState:\(newState.debugDescription)")
}

View File

@ -12,6 +12,7 @@ enum CallState: String {
case remoteRinging
case localRinging
case connected
case reconnecting
case localFailure // terminal
case localHangup // terminal
case remoteHangup // terminal
@ -47,7 +48,7 @@ protocol CallObserver: class {
switch state {
case .localFailure, .localHangup, .remoteHangup, .remoteBusy:
return true
case .idle, .dialing, .answering, .remoteRinging, .localRinging, .connected:
case .idle, .dialing, .answering, .remoteRinging, .localRinging, .connected, .reconnecting:
return false
}
}
@ -87,12 +88,11 @@ protocol CallObserver: class {
Logger.debug("\(TAG) state changed: \(oldValue) -> \(self.state) for call: \(self.identifiersForLogs)")
// Update connectedDate
if self.state == .connected {
if case .connected = self.state {
// if it's the first time we've connected (not a reconnect)
if connectedDate == nil {
connectedDate = NSDate()
}
} else {
connectedDate = nil
}
updateCallRecordType()

View File

@ -875,6 +875,9 @@
/* Call setup status label */
"IN_CALL_CONNECTING" = "Connecting…";
/* Call setup status label */
"IN_CALL_RECONNECTING" = "Reconnecting...";
/* Call setup status label */
"IN_CALL_RINGING" = "Ringing…";