diff --git a/README.md b/README.md index 2d89bf12..51b454dd 100644 --- a/README.md +++ b/README.md @@ -69,13 +69,13 @@ RNCallKeep.setup(options); Cancel button label - `okButton`: string (required) Ok button label - + ## Methods ### setAvailable _This feature is available only on Android._ -Tell _ConnectionService_ that the device is ready to accept outgoing calls. +Tell _ConnectionService_ that the device is ready to accept outgoing calls. If not the user will be stuck in the build UI screen without any actions. Eg: Call it with `false` when disconnected from the sip client, when your token expires ... @@ -207,6 +207,25 @@ _This feature is available only on Android._ await RNCallKeep.hasPhoneAccount(); ``` +### hasDefaultPhoneAccount + +Checks if the user has set a default [phone account](https://developer.android.com/reference/android/telecom/PhoneAccount). +If the user has not set a default they will be prompted to do so with an alert. + +This is a workaround for an [issue](https://github.com/wazo-pbx/react-native-callkeep/issues/33) affecting some Samsung devices. + +_This feature is available only on Android._ + +```js +const options = { + alertTitle: 'Default not set', + alertDescription: 'Please set the default phone account' +}; + +RNCallKeep.hasDefaultPhoneAccount(options); +``` + + ## Events ### didReceiveStartCallAction @@ -219,7 +238,7 @@ After all works are done, remember to call `RNCallKeep.startCall(uuid, calleeNum ```js RNCallKeep.addEventListener('didReceiveStartCallAction', ({ handle }) => { - + }); ``` @@ -283,7 +302,7 @@ A call was muted by the system or the user: ```js RNCallKeep.addEventListener('didPerformSetMutedCallAction', (muted) => { - + }); ``` @@ -293,7 +312,7 @@ A call was held or unheld by the current user ```js RNCallKeep.addEventListener('didToggleHoldCallAction', ({ hold, callUUID }) => { - + }); ``` @@ -307,7 +326,7 @@ Used type a number on his dialer ```js RNCallKeep.addEventListener('didPerformDTMFAction', ({ dtmf, callUUID }) => { - + }); ``` @@ -327,9 +346,9 @@ import uuid from 'uuid'; class RNCallKeepExample extends React.Component { constructor(props) { super(props); - + this.currentCallId = null; - + // Initialise RNCallKeep const options = { ios: { @@ -342,7 +361,7 @@ class RNCallKeepExample extends React.Component { okButton: 'ok', } }; - + try { RNCallKeep.setup(options); @@ -369,13 +388,13 @@ class RNCallKeepExample extends React.Component { onAnswerCallAction = ({ callUUID }) => { // called when the user answer the incoming call }; - + onEndCallAction = ({ callUUID }) => { RNCallKeep.endCall(this.getCurrentCallId()); - + this.currentCallId = null; }; - + onIncomingCallDisplayed = error => { // You will get this event after RNCallKeep finishes showing incoming call UI // You can check if there was an error while displaying @@ -389,7 +408,7 @@ class RNCallKeepExample extends React.Component { // you might want to do following things when receiving this event: // - Start playing ringback if it is an outgoing call }; - + getCurrentCallId = () => { if (!this.currentCallId) { this.currentCallId = uuid.v4(); diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index ef149618..9eb5933f 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -2,4 +2,5 @@ + diff --git a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java index b4c8073a..5e14c03b 100644 --- a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java +++ b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java @@ -176,6 +176,21 @@ public void checkPhoneAccountPermission(Promise promise) { promise.resolve(hasPhoneAccount()); } + @ReactMethod + public void checkDefaultPhoneAccount(Promise promise) { + if (!isConnectionServiceAvailable() || !hasPhoneAccount()) { + promise.resolve(true); + return; + } + + if (!Build.MANUFACTURER.equalsIgnoreCase("Samsung")) { + promise.resolve(true); + return; + } + + promise.resolve(telecomManager.getDefaultOutgoingPhoneAccount("tel") != null); + } + @ReactMethod public void hasPhoneAccount(Promise promise) { promise.resolve(hasPhoneAccount()); @@ -217,6 +232,15 @@ public void openPhoneAccounts() { return; } + openPhoneAccountSettings(); + } + + @ReactMethod + public void openPhoneAccountSettings() { + if (!isConnectionServiceAvailable()) { + return; + } + Intent intent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); this.getAppContext().startActivity(intent); diff --git a/index.js b/index.js index 18d88809..f511b185 100644 --- a/index.js +++ b/index.js @@ -37,6 +37,14 @@ class RNCallKeep { return this._setupIOS(options.ios); }; + hasDefaultPhoneAccount = async (options) => { + if (!isIOS) { + return this._hasDefaultPhoneAccount(options); + } + + return; + }; + displayIncomingCall = (uuid, handle, localizedCallerName, handleType = 'number', hasVideo = false) => { if (!isIOS) { RNCallKeepModule.displayIncomingCall(handle, localizedCallerName); @@ -121,33 +129,44 @@ class RNCallKeep { _setupAndroid = async (options) => { const hasAccount = await RNCallKeepModule.checkPhoneAccountPermission(); + const shouldOpenAccounts = await this._alert(options, hasAccount); + + if (shouldOpenAccounts) { + RNCallKeepModule.openPhoneAccounts(); + } + }; + + _hasDefaultPhoneAccount = async (options) => { + const hasDefault = await RNCallKeepModule.checkDefaultPhoneAccount(); + const shouldOpenAccounts = await this._alert(options, hasDefault); - return new Promise((resolve, reject) => { - if (hasAccount) { - return resolve(); - } - - Alert.alert( - options.alertTitle, - options.alertDescription, - [ - { - text: options.cancelButton, - onPress: reject, - style: 'cancel', - }, - { text: options.okButton, - onPress: () => { - RNCallKeepModule.openPhoneAccounts(); - resolve(); - } - }, - ], - { cancelable: true }, - ); - }); + if (shouldOpenAccounts) { + RNCallKeepModule.openPhoneAccountSettings(); + } }; + _alert = async (options, condition) => new Promise((resolve, reject) => { + if (condition) { + return resolve(false); + } + + Alert.alert( + options.alertTitle, + options.alertDescription, + [ + { + text: options.cancelButton, + onPress: reject, + style: 'cancel', + }, + { text: options.okButton, + onPress: () => resolve(true) + }, + ], + { cancelable: true }, + ); + }); + backToForeground() { if (isIOS) { return;