android: disable ConnectionService if permissions are not granted

Some devices seem to have a bug in their Android versions and startCall fails
with SecurityError because the CALL_PHONE permissions is not granted. This is
not a requirement for self-managed connection services as per the official
documentation though:
https://developer.android.com/guide/topics/connectivity/telecom/selfManaged

Alas, connection services takes over audio device management too, so let's
handle the error and disable CS if we get SecurityError.
This commit is contained in:
Saúl Ibarra Corretgé 2019-11-27 12:08:54 +01:00 committed by Saúl Ibarra Corretgé
parent 1a3736bf98
commit 58bd48c1ae
2 changed files with 21 additions and 3 deletions

View File

@ -116,7 +116,11 @@ class RNConnectionService extends ReactContextBaseJavaModule {
tm.unregisterPhoneAccount(accountHandle); tm.unregisterPhoneAccount(accountHandle);
} }
ConnectionService.unregisterStartCallPromise(callUUID); ConnectionService.unregisterStartCallPromise(callUUID);
promise.reject(e); if (e instanceof SecurityException) {
promise.reject("SECURITY_ERROR", "Required permissions not granted.");
} else {
promise.reject(e);
}
} }
} }

View File

@ -1,6 +1,6 @@
// @flow // @flow
import { Alert, Platform } from 'react-native'; import { Alert, NativeModules, Platform } from 'react-native';
import uuid from 'uuid'; import uuid from 'uuid';
import { createTrackMutedEvent, sendAnalytics } from '../../analytics'; import { createTrackMutedEvent, sendAnalytics } from '../../analytics';
@ -36,6 +36,7 @@ import CallKit from './CallKit';
import ConnectionService from './ConnectionService'; import ConnectionService from './ConnectionService';
import { isCallIntegrationEnabled } from './functions'; import { isCallIntegrationEnabled } from './functions';
const { AudioMode } = NativeModules;
const CallIntegration = CallKit || ConnectionService; const CallIntegration = CallKit || ConnectionService;
/** /**
@ -276,7 +277,8 @@ function _conferenceWillJoin({ dispatch, getState }, next, action) {
} }
}) })
.catch(error => { .catch(error => {
// Currently this error code is emitted only by Android. // Currently this error codes are emitted only by Android.
//
if (error.code === 'CREATE_OUTGOING_CALL_FAILED') { if (error.code === 'CREATE_OUTGOING_CALL_FAILED') {
// We're not tracking the call anymore - it doesn't exist on // We're not tracking the call anymore - it doesn't exist on
// the native side. // the native side.
@ -290,6 +292,18 @@ function _conferenceWillJoin({ dispatch, getState }, next, action) {
{ text: 'OK' } { text: 'OK' }
], ],
{ cancelable: false }); { 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);
// Set the desired audio mode, since we just reset the whole thing.
AudioMode.setMode(hasVideo ? AudioMode.VIDEO_CALL : AudioMode.AUDIO_CALL);
}
} }
}); });