diff --git a/README.md b/README.md index a2d81997..4a69349f 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,21 @@ Be sure to set this only after your call is ready for two way audio; used both i RNCallKeep.setCurrentCallActive(uuid); ``` +- `uuid`: string + - The `uuid` used for `startCall` or `displayIncomingCall` + +### isCallActive +_This feature is available only on IOS._ + +Returns true if the UUID passed matches an existing and answered call. +This will return true ONLY if the call exists and the user has already answered the call. It will return false +if the call does not exist or has not been answered. This is exposed to both React Native and Native sides. +This was exposed so a call can be canceled if ringing and the user answered on a different device. + +```js +RNCallKeep.isCallActive(uuid); +``` + - `uuid`: string - The `uuid` used for `startCall` or `displayIncomingCall` @@ -160,6 +175,13 @@ RNCallKeep.displayIncomingCall(uuid, handle, localizedCallerName); - `hasVideo`: boolean (optional, iOS only) - `false` (default) - `true` (you know... when not false) +- `options`: object (optional) + - `ios`: object + - `supportsHolding`: boolean (optional, default true) + - `supportsDTMF`: boolean (optional, default true) + - `supportsGrouping`: boolean (optional, default true) + - `supportsUngrouping`: boolean (optional, default true) + - `android`: object (currently no-op) ### answerIncomingCall _This feature is available only on Android._ @@ -215,6 +237,14 @@ RNCallKeep.updateDisplay(uuid, displayName, handle) - Name of the caller to be displayed on the native UI - `handle`: string - Phone number of the caller +- `options`: object (optional) + - `ios`: object + - `hasVideo`: boolean (optional) + - `supportsHolding`: boolean (optional) + - `supportsDTMF`: boolean (optional) + - `supportsGrouping`: boolean (optional) + - `supportsUngrouping`: boolean (optional) + - `android`: object (currently no-op) ### endCall @@ -371,6 +401,15 @@ const options = { RNCallKeep.hasDefaultPhoneAccount(options); ``` +### backToForeground +_This feature is available only on Android._ + +Use this to display the application in foreground if the application was in background state. +This method will open the application if it was closed. + +```js +RNCallKeep.backToForeground(); +``` ## Events @@ -673,9 +712,7 @@ Since iOS 13, you'll have to report the incoming calls that wakes up your applic // NSString *handle = @"caller number here"; // NSDictionary *extra = [payload.dictionaryPayload valueForKeyPath:@"custom.path.to.data"]; /* use this to pass any special data (ie. from your notification) down to RN. Can also be `nil` */ - [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES payload:extra]; - - completion(); + [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES payload:extra withCompletionHandler:completion]; } ``` diff --git a/android/src/main/java/io/wazo/callkeep/Constants.java b/android/src/main/java/io/wazo/callkeep/Constants.java new file mode 100644 index 00000000..4310de56 --- /dev/null +++ b/android/src/main/java/io/wazo/callkeep/Constants.java @@ -0,0 +1,19 @@ +package io.wazo.callkeep; + +public class Constants { + public static final String ACTION_ANSWER_CALL = "ACTION_ANSWER_CALL"; + public static final String ACTION_AUDIO_SESSION = "ACTION_AUDIO_SESSION"; + public static final String ACTION_CHECK_REACHABILITY = "ACTION_CHECK_REACHABILITY"; + public static final String ACTION_DTMF_TONE = "ACTION_DTMF_TONE"; + public static final String ACTION_END_CALL = "ACTION_END_CALL"; + public static final String ACTION_HOLD_CALL = "ACTION_HOLD_CALL"; + public static final String ACTION_MUTE_CALL = "ACTION_MUTE_CALL"; + public static final String ACTION_ONGOING_CALL = "ACTION_ONGOING_CALL"; + public static final String ACTION_UNHOLD_CALL = "ACTION_UNHOLD_CALL"; + public static final String ACTION_UNMUTE_CALL = "ACTION_UNMUTE_CALL"; + public static final String ACTION_WAKE_APP = "ACTION_WAKE_APP"; + + public static final String EXTRA_CALL_NUMBER = "EXTRA_CALL_NUMBER"; + public static final String EXTRA_CALL_UUID = "EXTRA_CALL_UUID"; + public static final String EXTRA_CALLER_NAME = "EXTRA_CALLER_NAME"; +} diff --git a/android/src/main/java/io/wazo/callkeep/RNCallKeepBackgroundMessagingService.java b/android/src/main/java/io/wazo/callkeep/RNCallKeepBackgroundMessagingService.java index 8770342f..c0690727 100644 --- a/android/src/main/java/io/wazo/callkeep/RNCallKeepBackgroundMessagingService.java +++ b/android/src/main/java/io/wazo/callkeep/RNCallKeepBackgroundMessagingService.java @@ -26,9 +26,9 @@ import com.facebook.react.bridge.Arguments; import com.facebook.react.jstasks.HeadlessJsTaskConfig; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALLER_NAME; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALL_NUMBER; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALL_UUID; +import static io.wazo.callkeep.Constants.EXTRA_CALLER_NAME; +import static io.wazo.callkeep.Constants.EXTRA_CALL_NUMBER; +import static io.wazo.callkeep.Constants.EXTRA_CALL_UUID; import javax.annotation.Nullable; diff --git a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java index 124de3ba..25a06261 100644 --- a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java +++ b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java @@ -32,6 +32,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.view.WindowManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; @@ -55,6 +56,7 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.HeadlessJsTaskService; import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; import java.lang.reflect.Array; @@ -67,26 +69,26 @@ import static android.support.v4.app.ActivityCompat.requestPermissions; +import static io.wazo.callkeep.Constants.EXTRA_CALLER_NAME; +import static io.wazo.callkeep.Constants.EXTRA_CALL_UUID; +import static io.wazo.callkeep.Constants.EXTRA_CALL_NUMBER; +import static io.wazo.callkeep.Constants.ACTION_END_CALL; +import static io.wazo.callkeep.Constants.ACTION_ANSWER_CALL; +import static io.wazo.callkeep.Constants.ACTION_MUTE_CALL; +import static io.wazo.callkeep.Constants.ACTION_UNMUTE_CALL; +import static io.wazo.callkeep.Constants.ACTION_DTMF_TONE; +import static io.wazo.callkeep.Constants.ACTION_HOLD_CALL; +import static io.wazo.callkeep.Constants.ACTION_UNHOLD_CALL; +import static io.wazo.callkeep.Constants.ACTION_ONGOING_CALL; +import static io.wazo.callkeep.Constants.ACTION_AUDIO_SESSION; +import static io.wazo.callkeep.Constants.ACTION_CHECK_REACHABILITY; +import static io.wazo.callkeep.Constants.ACTION_WAKE_APP; + // @see https://github.com/kbagchiGWC/voice-quickstart-android/blob/9a2aff7fbe0d0a5ae9457b48e9ad408740dfb968/exampleConnectionService/src/main/java/com/twilio/voice/examples/connectionservice/VoiceConnectionServiceActivity.java public class RNCallKeepModule extends ReactContextBaseJavaModule { public static final int REQUEST_READ_PHONE_STATE = 1337; public static final int REQUEST_REGISTER_CALL_PROVIDER = 394859; - public static final String CHECKING_PERMS = "CHECKING_PERMS"; - public static final String EXTRA_CALLER_NAME = "EXTRA_CALLER_NAME"; - public static final String EXTRA_CALL_UUID = "EXTRA_CALL_UUID"; - public static final String EXTRA_CALL_NUMBER = "EXTRA_CALL_NUMBER"; - public static final String ACTION_END_CALL = "ACTION_END_CALL"; - public static final String ACTION_ANSWER_CALL = "ACTION_ANSWER_CALL"; - public static final String ACTION_MUTE_CALL = "ACTION_MUTE_CALL"; - public static final String ACTION_UNMUTE_CALL = "ACTION_UNMUTE_CALL"; - public static final String ACTION_DTMF_TONE = "ACTION_DTMF_TONE"; - public static final String ACTION_HOLD_CALL = "ACTION_HOLD_CALL"; - public static final String ACTION_UNHOLD_CALL = "ACTION_UNHOLD_CALL"; - public static final String ACTION_ONGOING_CALL = "ACTION_ONGOING_CALL"; - public static final String ACTION_AUDIO_SESSION = "ACTION_AUDIO_SESSION"; - public static final String ACTION_CHECK_REACHABILITY = "ACTION_CHECK_REACHABILITY"; - private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST"; private static final String REACT_NATIVE_MODULE_NAME = "RNCallKeep"; private static final String[] permissions = { Manifest.permission.READ_PHONE_STATE, @@ -122,6 +124,7 @@ public void setup(ReadableMap options) { this.registerPhoneAccount(this.getAppContext()); voiceBroadcastReceiver = new VoiceBroadcastReceiver(); registerReceiver(); + VoiceConnectionService.setPhoneAccountHandle(handle); VoiceConnectionService.setAvailable(true); } } @@ -418,11 +421,22 @@ public void backToForeground() { Context context = getAppContext(); String packageName = context.getApplicationContext().getPackageName(); Intent focusIntent = context.getPackageManager().getLaunchIntentForPackage(packageName).cloneFilter(); + Activity activity = getCurrentActivity(); + boolean isOpened = activity != null; + Log.d(TAG, "backToForeground, app isOpened ?" + (isOpened ? "true" : "false")); + + if (isOpened) { + focusIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + activity.startActivity(focusIntent); + } else { - focusIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + focusIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + + WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + + WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - Activity activity = getCurrentActivity(); - activity.startActivity(focusIntent); + getReactApplicationContext().startActivity(focusIntent); + } } private void registerPhoneAccount(Context appContext) { @@ -568,6 +582,18 @@ public void onReceive(Context context, Intent intent) { case ACTION_CHECK_REACHABILITY: sendEventToJS("RNCallKeepCheckReachability", null); break; + case ACTION_WAKE_APP: + Intent headlessIntent = new Intent(reactContext, RNCallKeepBackgroundMessagingService.class); + headlessIntent.putExtra("callUUID", attributeMap.get(EXTRA_CALL_UUID)); + headlessIntent.putExtra("name", attributeMap.get(EXTRA_CALLER_NAME)); + headlessIntent.putExtra("handle", attributeMap.get(EXTRA_CALL_NUMBER)); + Log.d(TAG, "wakeUpApplication: " + attributeMap.get(EXTRA_CALL_UUID) + ", number : " + attributeMap.get(EXTRA_CALL_NUMBER) + ", displayName:" + attributeMap.get(EXTRA_CALLER_NAME)); + + ComponentName name = reactContext.startService(headlessIntent); + if (name != null) { + HeadlessJsTaskService.acquireWakeLockNow(reactContext); + } + break; } } } diff --git a/android/src/main/java/io/wazo/callkeep/VoiceConnection.java b/android/src/main/java/io/wazo/callkeep/VoiceConnection.java index bb19b369..db788d54 100644 --- a/android/src/main/java/io/wazo/callkeep/VoiceConnection.java +++ b/android/src/main/java/io/wazo/callkeep/VoiceConnection.java @@ -37,17 +37,17 @@ import java.util.HashMap; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_ANSWER_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_AUDIO_SESSION; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_DTMF_TONE; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_END_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_HOLD_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_MUTE_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_UNHOLD_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_UNMUTE_CALL; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALLER_NAME; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALL_NUMBER; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALL_UUID; +import static io.wazo.callkeep.Constants.ACTION_ANSWER_CALL; +import static io.wazo.callkeep.Constants.ACTION_AUDIO_SESSION; +import static io.wazo.callkeep.Constants.ACTION_DTMF_TONE; +import static io.wazo.callkeep.Constants.ACTION_END_CALL; +import static io.wazo.callkeep.Constants.ACTION_HOLD_CALL; +import static io.wazo.callkeep.Constants.ACTION_MUTE_CALL; +import static io.wazo.callkeep.Constants.ACTION_UNHOLD_CALL; +import static io.wazo.callkeep.Constants.ACTION_UNMUTE_CALL; +import static io.wazo.callkeep.Constants.EXTRA_CALLER_NAME; +import static io.wazo.callkeep.Constants.EXTRA_CALL_NUMBER; +import static io.wazo.callkeep.Constants.EXTRA_CALL_UUID; @TargetApi(Build.VERSION_CODES.M) public class VoiceConnection extends Connection { diff --git a/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java b/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java index f6480da7..cae0399f 100644 --- a/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java +++ b/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java @@ -41,8 +41,6 @@ import android.app.ActivityManager.RunningTaskInfo; import com.facebook.react.HeadlessJsTaskService; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.common.LifecycleState; import java.util.ArrayList; import java.util.HashMap; @@ -53,20 +51,13 @@ import java.util.UUID; import java.util.stream.Collectors; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_ANSWER_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_AUDIO_SESSION; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_DTMF_TONE; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_END_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_HOLD_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_MUTE_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_ONGOING_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_UNHOLD_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_UNMUTE_CALL; -import static io.wazo.callkeep.RNCallKeepModule.ACTION_CHECK_REACHABILITY; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALLER_NAME; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALL_NUMBER; -import static io.wazo.callkeep.RNCallKeepModule.EXTRA_CALL_UUID; -import static io.wazo.callkeep.RNCallKeepModule.handle; +import static io.wazo.callkeep.Constants.ACTION_AUDIO_SESSION; +import static io.wazo.callkeep.Constants.ACTION_ONGOING_CALL; +import static io.wazo.callkeep.Constants.ACTION_CHECK_REACHABILITY; +import static io.wazo.callkeep.Constants.ACTION_WAKE_APP; +import static io.wazo.callkeep.Constants.EXTRA_CALLER_NAME; +import static io.wazo.callkeep.Constants.EXTRA_CALL_NUMBER; +import static io.wazo.callkeep.Constants.EXTRA_CALL_UUID; // @see https://github.com/kbagchiGWC/voice-quickstart-android/blob/9a2aff7fbe0d0a5ae9457b48e9ad408740dfb968/exampleConnectionService/src/main/java/com/twilio/voice/examples/connectionservice/VoiceConnectionService.java @TargetApi(Build.VERSION_CODES.M) @@ -76,6 +67,7 @@ public class VoiceConnectionService extends ConnectionService { private static Boolean isReachable; private static String notReachableCallUuid; private static ConnectionRequest currentConnectionRequest; + private static PhoneAccountHandle phoneAccountHandle; private static String TAG = "RNCK:VoiceConnectionService"; public static Map currentConnections = new HashMap<>(); public static Boolean hasOutgoingCall = false; @@ -98,6 +90,10 @@ public VoiceConnectionService() { currentConnectionService = this; } + public static void setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) { + VoiceConnectionService.phoneAccountHandle = phoneAccountHandle; + } + public static void setAvailable(Boolean value) { Log.d(TAG, "setAvailable: " + (value ? "true" : "false")); if (value) { @@ -271,9 +267,7 @@ public void onConference(Connection connection1, Connection connection2) { VoiceConnection voiceConnection1 = (VoiceConnection) connection1; VoiceConnection voiceConnection2 = (VoiceConnection) connection2; - PhoneAccountHandle phoneAccountHandle = RNCallKeepModule.handle; - - VoiceConference voiceConference = new VoiceConference(handle); + VoiceConference voiceConference = new VoiceConference(phoneAccountHandle); voiceConference.addConnection(voiceConnection1); voiceConference.addConnection(voiceConnection2); diff --git a/index.d.ts b/index.d.ts index 2f86c02a..7008c6c1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -53,6 +53,10 @@ export default class RNCallKeep { static hasDefaultPhoneAccount(): boolean { + } + + static answerIncomingCall(uuid: string) { + } static displayIncomingCall( @@ -61,6 +65,7 @@ export default class RNCallKeep { localizedCallerName?: string, handleType?: HandleType, hasVideo?: boolean, + options?: object, ) { } @@ -78,6 +83,7 @@ export default class RNCallKeep { uuid: string, displayName: string, handle: string, + options?: object, ) { } @@ -114,7 +120,9 @@ export default class RNCallKeep { static setReachable() { } + static isCallActive(uuid: string): Promise { + } /** * @description supportConnectionService method is available only on Android. */ diff --git a/index.js b/index.js index 38b61301..d86b80b9 100644 --- a/index.js +++ b/index.js @@ -56,13 +56,19 @@ class RNCallKeep { return; }; - displayIncomingCall = (uuid, handle, localizedCallerName = '', handleType = 'number', hasVideo = false) => { + displayIncomingCall = (uuid, handle, localizedCallerName = '', handleType = 'number', hasVideo = false, options = null) => { if (!isIOS) { RNCallKeepModule.displayIncomingCall(uuid, handle, localizedCallerName); return; } - RNCallKeepModule.displayIncomingCall(uuid, handle, handleType, hasVideo, localizedCallerName); + // should be boolean type value + let supportsHolding = !!(options?.ios?.supportsHolding ?? true); + let supportsDTMF = !!(options?.ios?.supportsDTMF ?? true); + let supportsGrouping = !!(options?.ios?.supportsGrouping ?? true); + let supportsUngrouping = !!(options?.ios?.supportsUngrouping ?? true); + + RNCallKeepModule.displayIncomingCall(uuid, handle, handleType, hasVideo, localizedCallerName, supportsHolding, supportsDTMF, supportsGrouping, supportsUngrouping); }; answerIncomingCall = (uuid) => { @@ -108,6 +114,8 @@ class RNCallKeep { } }; + isCallActive = async(uuid) => await RNCallKeepModule.isCallActive(uuid); + endCall = (uuid) => RNCallKeepModule.endCall(uuid); endAllCalls = () => RNCallKeepModule.endAllCalls(); @@ -153,7 +161,20 @@ class RNCallKeep { RNCallKeepModule.setCurrentCallActive(callUUID); }; - updateDisplay = (uuid, displayName, handle) => RNCallKeepModule.updateDisplay(uuid, displayName, handle); + updateDisplay = (uuid, displayName, handle, options = null) => { + if (!isIOS) { + RNCallKeepModule.updateDisplay(uuid, displayName, handle); + return; + } + + let iosOptions = {}; + if (options && options.ios) { + iosOptions = { + ...options.ios, + } + } + RNCallKeepModule.updateDisplay(uuid, displayName, handle, iosOptions); + }; setOnHold = (uuid, shouldHold) => RNCallKeepModule.setOnHold(uuid, shouldHold); diff --git a/ios/RNCallKeep/RNCallKeep.h b/ios/RNCallKeep/RNCallKeep.h index 4447a780..47ce98b3 100644 --- a/ios/RNCallKeep/RNCallKeep.h +++ b/ios/RNCallKeep/RNCallKeep.h @@ -32,9 +32,17 @@ continueUserActivity:(NSUserActivity *)userActivity handleType:(NSString *)handleType hasVideo:(BOOL)hasVideo localizedCallerName:(NSString * _Nullable)localizedCallerName + supportsHolding:(BOOL)supportsHolding + supportsDTMF:(BOOL)supportsDTMF + supportsGrouping:(BOOL)supportsGrouping + supportsUngrouping:(BOOL)supportsUngrouping fromPushKit:(BOOL)fromPushKit - payload:(NSDictionary * _Nullable)payload; + payload:(NSDictionary * _Nullable)payload + withCompletionHandler:(void (^_Nullable)(void))completion; + (void)endCallWithUUID:(NSString *)uuidString reason:(int)reason; -@end \ No newline at end of file + ++ (BOOL)isCallActive:(NSString *)uuidString; + +@end diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 8cd01ea3..f3dc39da 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -149,9 +149,24 @@ + (void)initCallKitProvider { handle:(NSString *)handle handleType:(NSString *)handleType hasVideo:(BOOL)hasVideo - localizedCallerName:(NSString * _Nullable)localizedCallerName) -{ - [RNCallKeep reportNewIncomingCall: uuidString handle:handle handleType:handleType hasVideo:hasVideo localizedCallerName:localizedCallerName fromPushKit: NO payload:nil]; + localizedCallerName:(NSString * _Nullable)localizedCallerName + supportsHolding:(BOOL)supportsHolding + supportsDTMF:(BOOL)supportsDTMF + supportsGrouping:(BOOL)supportsGrouping + supportsUngrouping:(BOOL)supportsUngrouping) +{ + [RNCallKeep reportNewIncomingCall: uuidString + handle: handle + handleType: handleType + hasVideo: hasVideo + localizedCallerName: localizedCallerName + supportsHolding: supportsHolding + supportsDTMF: supportsDTMF + supportsGrouping: supportsGrouping + supportsUngrouping: supportsUngrouping + fromPushKit: NO + payload: nil + withCompletionHandler: nil]; } RCT_EXPORT_METHOD(startCall:(NSString *)uuidString @@ -234,7 +249,7 @@ + (void)initCallKitProvider { [RNCallKeep endCallWithUUID: uuidString reason:reason]; } -RCT_EXPORT_METHOD(updateDisplay:(NSString *)uuidString :(NSString *)displayName :(NSString *)uri) +RCT_EXPORT_METHOD(updateDisplay:(NSString *)uuidString :(NSString *)displayName :(NSString *)uri :(NSDictionary *)options) { #ifdef DEBUG NSLog(@"[RNCallKeep][updateDisplay] uuidString = %@ displayName = %@ uri = %@", uuidString, displayName, uri); @@ -244,6 +259,23 @@ + (void)initCallKitProvider { CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init]; callUpdate.localizedCallerName = displayName; callUpdate.remoteHandle = callHandle; + + if ([options valueForKey:@"hasVideo"] != nil) { + callUpdate.hasVideo = [RCTConvert BOOL:options[@"hasVideo"]]; + } + if ([options valueForKey:@"supportsHolding"] != nil) { + callUpdate.supportsHolding = [RCTConvert BOOL:options[@"supportsHolding"]]; + } + if ([options valueForKey:@"supportsDTMF"] != nil) { + callUpdate.supportsDTMF = [RCTConvert BOOL:options[@"supportsDTMF"]]; + } + if ([options valueForKey:@"supportsGrouping"] != nil) { + callUpdate.supportsGrouping = [RCTConvert BOOL:options[@"supportsGrouping"]]; + } + if ([options valueForKey:@"supportsUngrouping"] != nil) { + callUpdate.supportsUngrouping = [RCTConvert BOOL:options[@"supportsUngrouping"]]; + } + [self.callKeepProvider reportCallWithUUID:uuid updated:callUpdate]; } @@ -273,6 +305,14 @@ + (void)initCallKitProvider { [self requestTransaction:transaction]; } +RCT_EXPORT_METHOD(isCallActive:(NSString *)uuidString) +{ +#ifdef DEBUG + NSLog(@"[RNCallKeep][isCallActive] uuid = %@", uuidString); +#endif + [RNCallKeep isCallActive: uuidString]; +} + - (void)requestTransaction:(CXTransaction *)transaction { #ifdef DEBUG @@ -304,6 +344,20 @@ - (void)requestTransaction:(CXTransaction *)transaction }]; } ++ (BOOL)isCallActive:(NSString *)uuidString +{ + CXCallObserver *callObserver = [[CXCallObserver alloc] init]; + NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString]; + + for(CXCall *call in callObserver.calls){ + NSLog(@"[RNCallKeep] isCallActive %@ %d ?", call.UUID, [call.UUID isEqual:uuid]); + if([call.UUID isEqual:[[NSUUID alloc] initWithUUIDString:uuidString]] && !call.hasConnected){ + return true; + } + } + return false; +} + + (void)endCallWithUUID:(NSString *)uuidString reason:(int)reason { @@ -338,8 +392,13 @@ + (void)reportNewIncomingCall:(NSString *)uuidString handleType:(NSString *)handleType hasVideo:(BOOL)hasVideo localizedCallerName:(NSString * _Nullable)localizedCallerName + supportsHolding:(BOOL)supportsHolding + supportsDTMF:(BOOL)supportsDTMF + supportsGrouping:(BOOL)supportsGrouping + supportsUngrouping:(BOOL)supportsUngrouping fromPushKit:(BOOL)fromPushKit payload:(NSDictionary * _Nullable)payload + withCompletionHandler:(void (^_Nullable)(void))completion { #ifdef DEBUG NSLog(@"[RNCallKeep][reportNewIncomingCall] uuidString = %@", uuidString); @@ -348,10 +407,10 @@ + (void)reportNewIncomingCall:(NSString *)uuidString NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString]; CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init]; callUpdate.remoteHandle = [[CXHandle alloc] initWithType:_handleType value:handle]; - callUpdate.supportsDTMF = YES; - callUpdate.supportsHolding = YES; - callUpdate.supportsGrouping = YES; - callUpdate.supportsUngrouping = YES; + callUpdate.supportsHolding = supportsHolding; + callUpdate.supportsDTMF = supportsDTMF; + callUpdate.supportsGrouping = supportsGrouping; + callUpdate.supportsUngrouping = supportsUngrouping; callUpdate.hasVideo = hasVideo; callUpdate.localizedCallerName = localizedCallerName; @@ -364,6 +423,10 @@ + (void)reportNewIncomingCall:(NSString *)uuidString @"handle": handle, @"localizedCallerName": localizedCallerName ? localizedCallerName : @"", @"hasVideo": hasVideo ? @"1" : @"0", + @"supportsHolding": supportsHolding ? @"1" : @"0", + @"supportsDTMF": supportsDTMF ? @"1" : @"0", + @"supportsGrouping": supportsGrouping ? @"1" : @"0", + @"supportsUngrouping": supportsUngrouping ? @"1" : @"0", @"fromPushKit": fromPushKit ? @"1" : @"0", @"payload": payload ? payload : @"", }]; @@ -373,19 +436,12 @@ + (void)reportNewIncomingCall:(NSString *)uuidString [callKeep configureAudioSession]; } } + if (completion != nil) { + completion(); + } }]; } -+ (void)reportNewIncomingCall:(NSString *)uuidString - handle:(NSString *)handle - handleType:(NSString *)handleType - hasVideo:(BOOL)hasVideo - localizedCallerName:(NSString * _Nullable)localizedCallerName - fromPushKit:(BOOL)fromPushKit -{ - [RNCallKeep reportNewIncomingCall: uuidString handle:handle handleType:handleType hasVideo:hasVideo localizedCallerName:localizedCallerName fromPushKit: fromPushKit payload:nil]; -} - - (BOOL)lessThanIos10_2 { if (_version.majorVersion < 10) { @@ -425,7 +481,7 @@ + (CXProviderConfiguration *)getProviderConfiguration:(NSDictionary*)settings int _handleType = [RNCallKeep getHandleType:settings[@"handleType"]]; providerConfiguration.supportedHandleTypes = [NSSet setWithObjects:[NSNumber numberWithInteger:_handleType], nil]; }else{ - providerConfiguration.supportedHandleTypes = [NSSet setWithObjects:[NSNumber numberWithInteger:CXHandleTypeGeneric], nil]; + providerConfiguration.supportedHandleTypes = [NSSet setWithObjects:[NSNumber numberWithInteger:CXHandleTypePhoneNumber], nil]; } if (settings[@"supportsVideo"]) { providerConfiguration.supportsVideo = [settings[@"supportsVideo"] boolValue]; diff --git a/package.json b/package.json index 0692d211..43388ee4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-callkeep", - "version": "3.0.12", + "version": "3.0.15", "description": "iOS 10 CallKit and Android ConnectionService Framework For React Native", "main": "index.js", "scripts": {},