From 7ddd9487294393d385de8e0b6ad956890dc727be Mon Sep 17 00:00:00 2001 From: Luxi Liu Date: Sun, 1 Nov 2020 23:09:58 +1100 Subject: [PATCH] Add support of self managed call --- README.md | 15 +++++++++++++++ actions.js | 5 +++++ .../src/main/java/io/wazo/callkeep/Constants.java | 1 + .../java/io/wazo/callkeep/RNCallKeepModule.java | 10 ++++++++++ .../java/io/wazo/callkeep/VoiceConnection.java | 9 +++++++++ .../io/wazo/callkeep/VoiceConnectionService.java | 7 +++++++ example/App.js | 8 ++++++++ example/android/app/src/main/AndroidManifest.xml | 1 + example/android/gradle.properties | 3 +++ example/package.json | 5 +++-- index.d.ts | 2 ++ 11 files changed, 64 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 459a7a42..66ad799d 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ RNCallKeep.setup(options).then(accepted => {}); The image to use in the Android Phone application's native UI for enabling/disabling calling accounts. Should be a 48x48 HDPI grayscale PNG image. Must be in your drawable resources for the parent application. Must be lowercase and underscore (_) characters only, as Java doesn't like capital letters on resources. + - `selfManaged`: boolean (optional) + If provided and set to `true`, the app will be a standalone calling app and don't want their calls to be integrated into the built-in phone app. - `additionalPermissions`: [PermissionsAndroid] (optional) Any additional permissions you'd like your app to have at first launch. Can be used to simplify permission flows and avoid multiple popups to the user at different times. @@ -422,6 +424,19 @@ RNCallKeep.addEventListener('didReceiveStartCallAction', ({ handle, callUUID, na - `name` (string) - Name of the callee +### - showIncomingCall + +Callback for `RNCallKeep.showIncomingCall` + +```js +RNCallKeep.addEventListener('showIncomingCall', ({ callUUID }) => { + // Do your normal `Show incoming call` actions here. +}); +``` + +- `callUUID` (string) + - The UUID of the call + ### - answerCall User answer the incoming call diff --git a/actions.js b/actions.js index 480c139e..fdd3b397 100644 --- a/actions.js +++ b/actions.js @@ -4,6 +4,7 @@ const RNCallKeepModule = NativeModules.RNCallKeep; const eventEmitter = new NativeEventEmitter(RNCallKeepModule); const RNCallKeepDidReceiveStartCallAction = 'RNCallKeepDidReceiveStartCallAction'; +const RNCallKeepPerformShowIncomingCallAction = 'RNCallKeepPerformShowIncomingCallAction'; const RNCallKeepPerformAnswerCallAction = 'RNCallKeepPerformAnswerCallAction'; const RNCallKeepPerformEndCallAction = 'RNCallKeepPerformEndCallAction'; const RNCallKeepDidActivateAudioSession = 'RNCallKeepDidActivateAudioSession'; @@ -26,6 +27,9 @@ const didReceiveStartCallAction = handler => { return eventEmitter.addListener(RNCallKeepDidReceiveStartCallAction, (data) => handler(data)); }; +const showIncomingCall = handler => + eventEmitter.addListener(RNCallKeepPerformShowIncomingCallAction, (data) => handler(data)); + const answerCall = handler => eventEmitter.addListener(RNCallKeepPerformAnswerCallAction, (data) => handler(data)); @@ -63,6 +67,7 @@ export const emit = (eventName, payload) => eventEmitter.emit(eventName, payload export const listeners = { didReceiveStartCallAction, + showIncomingCall, answerCall, endCall, didActivateAudioSession, diff --git a/android/src/main/java/io/wazo/callkeep/Constants.java b/android/src/main/java/io/wazo/callkeep/Constants.java index 4310de56..0010bcc0 100644 --- a/android/src/main/java/io/wazo/callkeep/Constants.java +++ b/android/src/main/java/io/wazo/callkeep/Constants.java @@ -1,6 +1,7 @@ package io.wazo.callkeep; public class Constants { + public static final String ACTION_SHOW_INCOMING_CALL = "ACTION_SHOW_INCOMING_CALL"; 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"; diff --git a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java index 2be6c772..9e0b9014 100644 --- a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java +++ b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java @@ -73,6 +73,7 @@ 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_SHOW_INCOMING_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; @@ -487,6 +488,10 @@ private void registerPhoneAccount(Context appContext) { builder.setIcon(icon); } + if (_settings != null && _settings.hasKey("selfManaged") && _settings.getBoolean("selfManaged")) { + builder.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED); + } + PhoneAccount account = builder.build(); telephonyManager = (TelephonyManager) this.getAppContext().getSystemService(Context.TELEPHONY_SERVICE); @@ -532,6 +537,7 @@ private void registerReceiver() { if (!isReceiverRegistered) { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ACTION_END_CALL); + intentFilter.addAction(ACTION_SHOW_INCOMING_CALL); intentFilter.addAction(ACTION_ANSWER_CALL); intentFilter.addAction(ACTION_MUTE_CALL); intentFilter.addAction(ACTION_UNMUTE_CALL); @@ -574,6 +580,10 @@ public void onReceive(Context context, Intent intent) { args.putString("callUUID", attributeMap.get(EXTRA_CALL_UUID)); sendEventToJS("RNCallKeepPerformEndCallAction", args); break; + case ACTION_SHOW_INCOMING_CALL: + args.putString("callUUID", attributeMap.get(EXTRA_CALL_UUID)); + sendEventToJS("RNCallKeepPerformShowIncomingCallAction", args); + break; case ACTION_ANSWER_CALL: args.putString("callUUID", attributeMap.get(EXTRA_CALL_UUID)); sendEventToJS("RNCallKeepPerformAnswerCallAction", args); diff --git a/android/src/main/java/io/wazo/callkeep/VoiceConnection.java b/android/src/main/java/io/wazo/callkeep/VoiceConnection.java index 3deced5d..262960a5 100644 --- a/android/src/main/java/io/wazo/callkeep/VoiceConnection.java +++ b/android/src/main/java/io/wazo/callkeep/VoiceConnection.java @@ -43,6 +43,7 @@ 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_SHOW_INCOMING_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; @@ -91,6 +92,14 @@ public void onCallAudioStateChanged(CallAudioState state) { sendCallRequestToActivity(isMuted ? ACTION_MUTE_CALL : ACTION_UNMUTE_CALL, handle); } + @Override + public void onShowIncomingCallUi() { + super.onShowIncomingCallUi(); + Log.d(TAG, "onShowIncomingCallUi called"); + + sendCallRequestToActivity(ACTION_SHOW_INCOMING_CALL, handle); + } + @Override public void onAnswer() { super.onAnswer(); diff --git a/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java b/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java index bbe8c3df..50610392 100644 --- a/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java +++ b/android/src/main/java/io/wazo/callkeep/VoiceConnectionService.java @@ -33,6 +33,7 @@ import android.telecom.ConnectionRequest; import android.telecom.ConnectionService; import android.telecom.DisconnectCause; +import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.util.Log; @@ -248,6 +249,12 @@ private Connection createConnection(ConnectionRequest request) { connection.setExtras(extras); currentConnections.put(extras.getString(EXTRA_CALL_UUID), connection); + TelecomManager telecomManager = (TelecomManager) this.getApplicationContext().getSystemService(Context.TELECOM_SERVICE); + PhoneAccount phoneAccount = telecomManager.getPhoneAccount(request.getAccountHandle()); + if ((phoneAccount.getCapabilities() & PhoneAccount.CAPABILITY_SELF_MANAGED) != 0) { + connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED); + } + // Get other connections for conferencing Map otherConnections = new HashMap<>(); for (Map.Entry entry : currentConnections.entrySet()) { diff --git a/example/App.js b/example/App.js index 82feed7c..5116a15a 100644 --- a/example/App.js +++ b/example/App.js @@ -45,6 +45,7 @@ RNCallKeep.setup({ alertDescription: 'This application needs to access your phone accounts', cancelButton: 'Cancel', okButton: 'ok', + selfManaged: true, }, }); @@ -107,6 +108,11 @@ export default function App() { }, 3000); }; + const showIncomingCall = ({ callUUID }) => { + const number = calls[callUUID]; + log(`[showIncomingCall] ${format(callUUID)}, number: ${number}`); + } + const answerCall = ({ callUUID }) => { const number = calls[callUUID]; log(`[answerCall] ${format(callUUID)}, number: ${number}`); @@ -197,6 +203,7 @@ export default function App() { }; useEffect(() => { + RNCallKeep.addEventListener('showIncomingCall', showIncomingCall); RNCallKeep.addEventListener('answerCall', answerCall); RNCallKeep.addEventListener('didPerformDTMFAction', didPerformDTMFAction); RNCallKeep.addEventListener('didReceiveStartCallAction', didReceiveStartCallAction); @@ -205,6 +212,7 @@ export default function App() { RNCallKeep.addEventListener('endCall', endCall); return () => { + RNCallKeep.removeEventListener('showIncomingCall', showIncomingCall); RNCallKeep.removeEventListener('answerCall', answerCall); RNCallKeep.removeEventListener('didPerformDTMFAction', didPerformDTMFAction); RNCallKeep.removeEventListener('didReceiveStartCallAction', didReceiveStartCallAction); diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index fe45aa1e..354c242e 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ + diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 89e0d99e..027ef9db 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -16,3 +16,6 @@ # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true + +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/package.json b/example/package.json index 3924f2ad..e1f72785 100644 --- a/example/package.json +++ b/example/package.json @@ -11,7 +11,7 @@ "react-dom": "^16.8.6", "react-native": "0.59.8", "react-native-background-timer": "^2.1.1", - "react-native-callkeep": "3.0.7", + "react-native-callkeep": "https://github.com/luxiliu/react-native-callkeep#allow-self-managed-call", "react-native-device-info": "^2.3.2", "react-native-gesture-handler": "~1.3.0", "react-native-reanimated": "~1.1.0", @@ -20,7 +20,8 @@ "uuid": "^3.3.2" }, "devDependencies": { - "babel-preset-expo": "^6.0.0" + "babel-preset-expo": "^6.0.0", + "jetifier": "^1.6.6" }, "private": true } diff --git a/index.d.ts b/index.d.ts index f8133789..98b2851f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,6 +1,7 @@ declare module 'react-native-callkeep' { export type Events = 'didReceiveStartCallAction' | + 'showIncomingCall' | 'answerCall' | 'endCall' | 'didActivateAudioSession' | @@ -30,6 +31,7 @@ declare module 'react-native-callkeep' { cancelButton: string, okButton: string, imageName?: string, + selfManaged?: boolean, additionalPermissions: string[], }, }