Show "Reconnecting..." on call screen

// FREEBIE
pull/1/head
Michael Kirk 7 years ago
parent 830ed884cf
commit 0f46834e8d

@ -676,6 +676,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
} }
} }
return formattedDate return formattedDate
case .reconnecting:
return NSLocalizedString("IN_CALL_RECONNECTING", comment: "Call setup status label")
case .remoteBusy: case .remoteBusy:
return NSLocalizedString("END_CALL_RESPONDER_IS_BUSY", comment: "Call setup status label") return NSLocalizedString("END_CALL_RESPONDER_IS_BUSY", comment: "Call setup status label")
case .localFailure: case .localFailure:
@ -694,18 +696,39 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
} }
} }
var isBlinkingReconnectLabel = false
func updateCallStatusLabel(callState: CallState) { func updateCallStatusLabel(callState: CallState) {
assert(Thread.isMainThread) assert(Thread.isMainThread)
let text = String(format: CallStrings.callStatusFormat, let text = String(format: CallStrings.callStatusFormat,
localizedTextForCallState(callState)) localizedTextForCallState(callState))
self.callStatusLabel.text = text 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) { func updateCallUI(callState: CallState) {
assert(Thread.isMainThread) assert(Thread.isMainThread)
updateCallStatusLabel(callState: callState) updateCallStatusLabel(callState: callState)
if isShowingSettingsNag { if isShowingSettingsNag {
settingsNagView.isHidden = false settingsNagView.isHidden = false
contactAvatarView.isHidden = true contactAvatarView.isHidden = true

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

@ -547,7 +547,7 @@ protocol CallServiceObserver: class {
// If both users are trying to call each other at the same time, // If both users are trying to call each other at the same time,
// both should see busy. // both should see busy.
handleRemoteBusy(thread: existingCall.thread, callId: existingCall.signalingId) 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 // If one user calls another while the other has a "vestigial" call with
// that same user, fail the old call. // that same user, fail the old call.
terminateCall() terminateCall()
@ -769,8 +769,31 @@ protocol CallServiceObserver: class {
Logger.info("\(self.logTag) call already ringing. Ignoring \(#function): \(call.identifiersForLogs).") Logger.info("\(self.logTag) call already ringing. Ignoring \(#function): \(call.identifiersForLogs).")
case .connected: case .connected:
Logger.info("\(self.logTag) Call reconnected \(#function): \(call.identifiersForLogs).") 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: 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 { switch call.state {
case .idle, .dialing, .answering, .localRinging, .localFailure, .remoteBusy, .remoteRinging: case .idle, .dialing, .answering, .localRinging, .localFailure, .remoteBusy, .remoteRinging:
handleMissedCall(call) handleMissedCall(call)
case .connected, .localHangup, .remoteHangup: case .connected, .reconnecting, .localHangup, .remoteHangup:
Logger.info("\(self.logTag) call is finished.") Logger.info("\(self.logTag) call is finished.")
} }
@ -1217,6 +1240,17 @@ protocol CallServiceObserver: class {
self.handleIceConnected() 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. * The connection failed to establish. The clients will not be able to communicate.
*/ */

@ -27,6 +27,7 @@ protocol PeerConnectionClientDelegate: class {
/** /**
* The connection has been established. The clients can now communicate. * 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) func peerConnectionClientIceConnected(_ peerconnectionClient: PeerConnectionClient)
@ -35,6 +36,13 @@ protocol PeerConnectionClientDelegate: class {
*/ */
func peerConnectionClientIceFailed(_ peerconnectionClient: PeerConnectionClient) 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 * 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 * 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: case .disconnected:
Logger.warn("\(self.TAG) RTCIceConnection 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: default:
Logger.debug("\(self.TAG) ignoring change IceConnectionState:\(newState.debugDescription)") Logger.debug("\(self.TAG) ignoring change IceConnectionState:\(newState.debugDescription)")
} }

@ -12,6 +12,7 @@ enum CallState: String {
case remoteRinging case remoteRinging
case localRinging case localRinging
case connected case connected
case reconnecting
case localFailure // terminal case localFailure // terminal
case localHangup // terminal case localHangup // terminal
case remoteHangup // terminal case remoteHangup // terminal
@ -47,7 +48,7 @@ protocol CallObserver: class {
switch state { switch state {
case .localFailure, .localHangup, .remoteHangup, .remoteBusy: case .localFailure, .localHangup, .remoteHangup, .remoteBusy:
return true return true
case .idle, .dialing, .answering, .remoteRinging, .localRinging, .connected: case .idle, .dialing, .answering, .remoteRinging, .localRinging, .connected, .reconnecting:
return false return false
} }
} }
@ -87,12 +88,11 @@ protocol CallObserver: class {
Logger.debug("\(TAG) state changed: \(oldValue) -> \(self.state) for call: \(self.identifiersForLogs)") Logger.debug("\(TAG) state changed: \(oldValue) -> \(self.state) for call: \(self.identifiersForLogs)")
// Update connectedDate // 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 { if connectedDate == nil {
connectedDate = NSDate() connectedDate = NSDate()
} }
} else {
connectedDate = nil
} }
updateCallRecordType() updateCallRecordType()

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

Loading…
Cancel
Save