diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 797acea5..00000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 43164570..c5439d81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.0.0+4 + +* Update README.md. +* Add func `activeCalls()` Get active calls +* Remove notification when click action `Call back` (Android). +* Bugs `no activation of the audio session` (iOS) +* Fixed some bugs. + ## 1.0.0+3 * Update README.md. diff --git a/README.md b/README.md index 58ee84b4..d58f0953 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ A Flutter plugin to show incoming call in your Flutter app(Custom for Android/Ca * Add pubspec.yaml: ```console dependencies: - flutter_callkit_incoming: ^1.0.0+2 + flutter_callkit_incoming: any ``` 2. Configure Project * Android @@ -116,6 +116,15 @@ A Flutter plugin to show incoming call in your Flutter app(Custom for Android/Ca await FlutterCallkitIncoming.endAllCalls(); ``` + * Get active calls. iOS: return active calls from Callkit, Android: only return last call + ```dart + await FlutterCallkitIncoming.activeCalls(); + ``` + Output + ```json + [{"id": "8BAA2B26-47AD-42C1-9197-1D75F662DF78"}] + ``` + * Listen events ```dart FlutterCallkitIncoming.onEvent.listen((event) { @@ -221,6 +230,12 @@ A Flutter plugin to show incoming call in your Flutter app(Custom for Android/Ca * https://github.com/hiennguyen92/flutter_callkit_incoming
+ +6. Todo + * Add `WakeLock` (background tasks) for Android + * Switch using `service` for Android + +
## :bulb: Demo 1. Demo Illustration: diff --git a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitIncomingBroadcastReceiver.kt b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitIncomingBroadcastReceiver.kt index 9e26d843..07ac66f2 100644 --- a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitIncomingBroadcastReceiver.kt +++ b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitIncomingBroadcastReceiver.kt @@ -151,9 +151,9 @@ class CallkitIncomingBroadcastReceiver : BroadcastReceiver() { } ACTION_CALL_CALLBACK -> { try { + callkitNotificationManager.clearMissCallNotification(data) sendEventFlutter(ACTION_CALL_CALLBACK, data) Utils.backToForeground(context) - callkitNotificationManager.clearMissCallNotification(data) val closeNotificationPanel = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) context.sendBroadcast(closeNotificationPanel) } catch (error: Exception) { diff --git a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt index c49f6bb2..4be7a66e 100644 --- a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt +++ b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt @@ -160,6 +160,7 @@ class CallkitNotificationManager(private val context: Context) { } fun showMissCallNotification(data: Bundle) { + notificationId = data.getString(EXTRA_CALLKIT_ID, "callkit_incoming").hashCode() createNotificationChanel() val missedCallSound: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val typeCall = data.getInt(EXTRA_CALLKIT_TYPE, -1) @@ -222,6 +223,12 @@ class CallkitNotificationManager(private val context: Context) { fun clearMissCallNotification(data: Bundle) { notificationId = data.getString(EXTRA_CALLKIT_ID, "callkit_incoming").hashCode() getNotificationManager().cancel(notificationId) + Handler(Looper.getMainLooper()).postDelayed({ + try { + getNotificationManager().cancel(notificationId) + } catch (error: Exception) { + } + }, 1000) } private fun createNotificationChanel() { @@ -286,7 +293,7 @@ class CallkitNotificationManager(private val context: Context) { context, id, acceptIntent, - PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_CANCEL_CURRENT ) } diff --git a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt index 8aaa1390..debfa852 100644 --- a/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt +++ b/android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/FlutterCallkitIncomingPlugin.kt @@ -14,6 +14,8 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result +import org.json.JSONArray +import org.json.JSONObject /** FlutterCallkitIncomingPlugin */ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { @@ -38,6 +40,7 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA private lateinit var callkitNotificationManager: CallkitNotificationManager private lateinit var channel: MethodChannel private lateinit var events: EventChannel + private var data: Data? = null override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { this.context = flutterPluginBinding.applicationContext @@ -54,24 +57,24 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA callkitNotificationManager = CallkitNotificationManager(this.context) when (call.method) { "showCallkitIncoming" -> { - val data = Data(call.arguments()) - data.from = "notification" - callkitNotificationManager.showIncomingNotification(data.toBundle()) + data = Data(call.arguments()) + data!!.from = "notification" + callkitNotificationManager.showIncomingNotification(data!!.toBundle()) //send BroadcastReceiver context.sendBroadcast( CallkitIncomingBroadcastReceiver.getIntentIncoming( context, - data.toBundle() + data!!.toBundle() ) ) result.success("OK") } "startCall" -> { - val data = Data(call.arguments()) + data = Data(call.arguments()) context.sendBroadcast( CallkitIncomingBroadcastReceiver.getIntentStart( context, - data.toBundle() + data!!.toBundle() ) ) result.success("OK") @@ -96,6 +99,15 @@ class FlutterCallkitIncomingPlugin : FlutterPlugin, MethodCallHandler, ActivityA ) result.success("OK") } + "activeCalls" -> { + val json = JSONArray() + if(data != null) { + val item = JSONObject() + item.put("id", data?.uuid) + json.put(item) + } + result.success(json.toString()) + } } } catch (error: Exception) { result.error("error", error.message, "") diff --git a/example/lib/main.dart b/example/lib/main.dart index eebcd057..a4cfc8b7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -111,6 +111,15 @@ class _MyAppState extends State { onPressed: () async { this.startOutGoingCall(); }, + ), + IconButton( + icon: Icon( + Icons.call_merge, + color: Colors.white, + ), + onPressed: () async { + this.activeCalls(); + }, ) ], ), @@ -139,7 +148,7 @@ class _MyAppState extends State { 'appName': 'Callkit', 'avatar': 'https://i.pravatar.cc/100', 'handle': '0123456789', - 'type': 1, + 'type': 0, 'duration': 30000, 'extra': {'userId': '1a2b3c4d'}, 'android': { @@ -188,4 +197,9 @@ class _MyAppState extends State { }; //number/email await FlutterCallkitIncoming.startCall(params); } + + Future activeCalls() async { + var calls = await FlutterCallkitIncoming.activeCalls(); + print(calls); + } } diff --git a/example/pubspec.lock b/example/pubspec.lock index ca26e4b7..88313eb2 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -75,7 +75,7 @@ packages: path: ".." relative: true source: path - version: "1.0.0+3" + version: "1.0.0+4" flutter_test: dependency: "direct dev" description: flutter diff --git a/ios/Classes/CallManager.swift b/ios/Classes/CallManager.swift index 52154ca7..f60d804c 100644 --- a/ios/Classes/CallManager.swift +++ b/ios/Classes/CallManager.swift @@ -46,6 +46,17 @@ class CallManager: NSObject { } } + func activeCalls() -> [[String: String]] { + let calls = callController.callObserver.calls + var json = [[String: String]]() + for call in calls { + let item: [String: String] = ["id": call.uuid.uuidString] + json.append(item) + } + return json + } + + func setHold(call: Call, onHold: Bool) { let handleCall = CXSetHeldCallAction(call: call.uuid, onHold: onHold) let callTransaction = CXTransaction() diff --git a/ios/Classes/SwiftFlutterCallkitIncomingPlugin.swift b/ios/Classes/SwiftFlutterCallkitIncomingPlugin.swift index f83d6b1a..b5494470 100644 --- a/ios/Classes/SwiftFlutterCallkitIncomingPlugin.swift +++ b/ios/Classes/SwiftFlutterCallkitIncomingPlugin.swift @@ -83,6 +83,9 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi } result("OK") break + case "activeCalls": + result(self.callManager?.activeCalls()) + break; case "endAllCalls": self.callManager?.endCallAlls() result("OK") @@ -113,8 +116,10 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi let uuid = UUID(uuidString: data.uuid) + configurAudioSession() self.sharedProvider?.reportNewIncomingCall(with: uuid!, update: callUpdate) { error in if(error == nil) { + self.configurAudioSession() let call = Call(uuid: uuid!) call.handle = data.handle self.callManager?.addCall(call) @@ -349,7 +354,7 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi call.isOnHold = action.isOnHold call.isMuted = action.isOnHold self.callManager?.setHold(call: call, onHold: action.isOnHold) - self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_HOLD, [ "uuid": action.callUUID, "isOnHold": action.isOnHold ]) + self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_HOLD, [ "id": action.callUUID.uuidString, "isOnHold": action.isOnHold ]) action.fulfill() } @@ -359,7 +364,7 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi return } call.isMuted = action.isMuted - self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_MUTE, [ "uuid": action.callUUID, "isMuted": action.isMuted ]) + self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_MUTE, [ "id": action.callUUID.uuidString, "isMuted": action.isMuted ]) action.fulfill() } @@ -369,7 +374,7 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi return } //call.isMuted = action.isMuted - self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_GROUP, [ "uuid": action.callUUID, "callUUIDToGroupWith" : action.callUUIDToGroupWith]) + self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_GROUP, [ "id": action.callUUID.uuidString, "callUUIDToGroupWith" : action.callUUIDToGroupWith?.uuidString]) action.fulfill() } @@ -379,7 +384,7 @@ public class SwiftFlutterCallkitIncomingPlugin: NSObject, FlutterPlugin, CXProvi return } //call.isMuted = action.isMuted - self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_DMTF, [ "uuid": action.callUUID, "digits": action.digits, "type": action.type ]) + self.sendEvent(SwiftFlutterCallkitIncomingPlugin.ACTION_CALL_TOGGLE_DMTF, [ "id": action.callUUID.uuidString, "digits": action.digits, "type": action.type ]) action.fulfill() } diff --git a/lib/flutter_callkit_incoming.dart b/lib/flutter_callkit_incoming.dart index f8fe2b89..ee057aa8 100644 --- a/lib/flutter_callkit_incoming.dart +++ b/lib/flutter_callkit_incoming.dart @@ -58,6 +58,13 @@ class FlutterCallkitIncoming { await _channel.invokeMethod("endAllCalls"); } + /// Get active calls. + /// On iOS: return active calls from Callkit. + /// On Android: only return last call + static Future activeCalls() async { + return await _channel.invokeMethod("activeCalls"); + } + static CallEvent? _receiveCallEvent(dynamic data) { var event = ""; dynamic body = {}; diff --git a/pubspec.yaml b/pubspec.yaml index e7e38921..709b8ec4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_callkit_incoming description: Flutter Callkit Incoming to show callkit screen in your Flutter app. -version: 1.0.0+3 +version: 1.0.0+4 homepage: https://github.com/hiennguyen92/flutter_callkit_incoming environment: