android: handle ConnectionService failures more resiliently
Some Samsung devices will fail to fully engage ConnectionService if no SIM card was ever installed on the device. We could check for it, but it would require the CALL_PHONE permission, which is not something we want to do, so fallback to not using ConnectionService.
This commit is contained in:
parent
1aaaae24ee
commit
a622a4c713
|
@ -123,14 +123,17 @@ public class ConnectionService extends android.telecom.ConnectionService {
|
|||
* {@link android.telecom.Connection#STATE_ACTIVE}.
|
||||
*
|
||||
* @param callUUID the call UUID which identifies the connection.
|
||||
* @return Whether the connection was set as active or not.
|
||||
*/
|
||||
static void setConnectionActive(String callUUID) {
|
||||
static boolean setConnectionActive(String callUUID) {
|
||||
ConnectionImpl connection = connections.get(callUUID);
|
||||
|
||||
if (connection != null) {
|
||||
connection.setActive();
|
||||
return true;
|
||||
} else {
|
||||
JitsiMeetLogger.e("%s setConnectionActive - no connection for UUID: %s", TAG, callUUID);
|
||||
JitsiMeetLogger.w("%s setConnectionActive - no connection for UUID: %s", TAG, callUUID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -158,8 +158,11 @@ class RNConnectionService extends ReactContextBaseJavaModule {
|
|||
@ReactMethod
|
||||
public void reportConnectedOutgoingCall(String callUUID, Promise promise) {
|
||||
JitsiMeetLogger.d(TAG + " reportConnectedOutgoingCall " + callUUID);
|
||||
ConnectionService.setConnectionActive(callUUID);
|
||||
promise.resolve(null);
|
||||
if (ConnectionService.setConnectionActive(callUUID)) {
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
promise.reject("CONNECTION_NOT_FOUND_ERROR", "Connection wasn't found.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -186,13 +186,25 @@ function _conferenceJoined({ getState }, next, action) {
|
|||
const { callUUID } = action.conference;
|
||||
|
||||
if (callUUID) {
|
||||
CallIntegration.reportConnectedOutgoingCall(callUUID).then(() => {
|
||||
// iOS 13 doesn't like the mute state to be false before the call is started
|
||||
// so we update it here in case the user selected startWithAudioMuted.
|
||||
if (Platform.OS === 'ios') {
|
||||
_updateCallIntegrationMuted(action.conference, getState());
|
||||
}
|
||||
});
|
||||
CallIntegration.reportConnectedOutgoingCall(callUUID)
|
||||
.then(() => {
|
||||
// iOS 13 doesn't like the mute state to be false before the call is started
|
||||
// so we update it here in case the user selected startWithAudioMuted.
|
||||
if (Platform.OS === 'ios') {
|
||||
_updateCallIntegrationMuted(action.conference, getState());
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// Currently this error code is emitted only by Android.
|
||||
//
|
||||
if (error.code === 'CONNECTION_NOT_FOUND_ERROR') {
|
||||
// Some Samsung devices will fail to fully engage ConnectionService if no SIM card
|
||||
// was ever installed on the device. We could check for it, but it would require
|
||||
// the CALL_PHONE permission, which is not something we want to do, so fallback to
|
||||
// not using ConnectionService.
|
||||
_handleConnectionServiceFailure(getState());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -294,22 +306,43 @@ function _conferenceWillJoin({ dispatch, getState }, next, action) {
|
|||
{ cancelable: false });
|
||||
} else if (error.code === 'SECURITY_ERROR') {
|
||||
// Some devices fail because the CALL_PHONE permission is not granted, which is
|
||||
// nonsense, because it's not needed for self-managed connections. Alas, this also
|
||||
// means audio device management would be broken, so fallback to not using ConnectionService.
|
||||
// NOTE: We are not storing this in Settings, in case it's a transient issue, as far fetched as
|
||||
// that may be.
|
||||
if (AudioMode.setUseConnectionService) {
|
||||
AudioMode.setUseConnectionService(false);
|
||||
// nonsense, because it's not needed for self-managed connections.
|
||||
|
||||
// Set the desired audio mode, since we just reset the whole thing.
|
||||
AudioMode.setMode(hasVideo ? AudioMode.VIDEO_CALL : AudioMode.AUDIO_CALL);
|
||||
}
|
||||
_handleConnectionServiceFailure(state);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a ConnectionService fatal error by falling back to non-ConnectionService device management.
|
||||
*
|
||||
* @param {Object} state - Redux store.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _handleConnectionServiceFailure(state: Object) {
|
||||
const conference = getCurrentConference(state);
|
||||
|
||||
if (conference) {
|
||||
// We're not tracking the call anymore.
|
||||
delete conference.callUUID;
|
||||
|
||||
// ConnectionService has fatally failed. Alas, this also means audio device management would be broken, so
|
||||
// fallback to not using ConnectionService.
|
||||
// NOTE: We are not storing this in Settings, in case it's a transient issue, as far fetched as
|
||||
// that may be.
|
||||
if (AudioMode.setUseConnectionService) {
|
||||
AudioMode.setUseConnectionService(false);
|
||||
|
||||
const hasVideo = !isVideoMutedByAudioOnly(state);
|
||||
|
||||
// Set the desired audio mode, since we just reset the whole thing.
|
||||
AudioMode.setMode(hasVideo ? AudioMode.VIDEO_CALL : AudioMode.AUDIO_CALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles CallKit's event {@code performEndCallAction}.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue