From 38e5b02b14a9e0e8369e1de31876640fd70d35ef Mon Sep 17 00:00:00 2001 From: Krille Date: Sun, 16 Feb 2025 11:30:16 +0100 Subject: [PATCH] refactor: Remove broken callkeep implementation --- lib/pages/chat_list/chat_list.dart | 2 - .../settings_chat/settings_chat_view.dart | 11 - lib/utils/push_helper.dart | 5 +- lib/utils/voip/callkeep_manager.dart | 325 ------------------ lib/utils/voip_plugin.dart | 57 +-- pubspec.lock | 8 - pubspec.yaml | 1 - 7 files changed, 16 insertions(+), 393 deletions(-) delete mode 100644 lib/utils/voip/callkeep_manager.dart diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index ce90f0d53..b1e18ac63 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -29,7 +29,6 @@ import 'package:fluffychat/widgets/share_scaffold_dialog.dart'; import '../../../utils/account_bundles.dart'; import '../../config/setting_keys.dart'; import '../../utils/url_launcher.dart'; -import '../../utils/voip/callkeep_manager.dart'; import '../../widgets/fluffy_chat_app.dart'; import '../../widgets/matrix.dart'; import '../bootstrap/bootstrap_dialog.dart'; @@ -409,7 +408,6 @@ class ChatListController extends State scrollController.addListener(_onScroll); _waitForFirstSync(); _hackyWebRTCFixForWeb(); - CallKeepManager().initialize(); WidgetsBinding.instance.addPostFrameCallback((_) async { if (mounted) { searchServer = diff --git a/lib/pages/settings_chat/settings_chat_view.dart b/lib/pages/settings_chat/settings_chat_view.dart index 7d9015429..3cd3baeb0 100644 --- a/lib/pages/settings_chat/settings_chat_view.dart +++ b/lib/pages/settings_chat/settings_chat_view.dart @@ -7,7 +7,6 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/utils/voip/callkeep_manager.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/settings_switch_list_tile.dart'; @@ -117,16 +116,6 @@ class SettingsChatView extends StatelessWidget { storeKey: SettingKeys.experimentalVoip, defaultValue: AppConfig.experimentalVoip, ), - if (PlatformInfos.isMobile) - ListTile( - title: Text(L10n.of(context).callingPermissions), - onTap: () => - CallKeepManager().checkoutPhoneAccountSetting(context), - trailing: const Padding( - padding: EdgeInsets.all(16.0), - child: Icon(Icons.call), - ), - ), ], ), ), diff --git a/lib/utils/push_helper.dart b/lib/utils/push_helper.dart index 508cd8acd..21b6bcff9 100644 --- a/lib/utils/push_helper.dart +++ b/lib/utils/push_helper.dart @@ -15,7 +15,6 @@ import 'package:fluffychat/utils/client_download_content_extension.dart'; import 'package:fluffychat/utils/client_manager.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/utils/voip/callkeep_manager.dart'; Future pushHelper( PushNotification notification, { @@ -120,9 +119,7 @@ Future _tryPushHelper( client.backgroundSync = true; } - if (event.type == EventTypes.CallInvite) { - CallKeepManager().initialize(); - } else if (event.type == EventTypes.CallHangup) { + if (event.type == EventTypes.CallHangup) { client.backgroundSync = false; } diff --git a/lib/utils/voip/callkeep_manager.dart b/lib/utils/voip/callkeep_manager.dart deleted file mode 100644 index a66252414..000000000 --- a/lib/utils/voip/callkeep_manager.dart +++ /dev/null @@ -1,325 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import 'package:callkeep/callkeep.dart'; -import 'package:flutter_foreground_task/flutter_foreground_task.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:matrix/matrix.dart'; -import 'package:permission_handler/permission_handler.dart'; - -class CallKeeper { - CallKeeper(this.callKeepManager, this.call) { - call.onCallStateChanged.stream.listen(_handleCallState); - } - - CallKeepManager callKeepManager; - bool? held = false; - bool? muted = false; - bool connected = false; - CallSession call; - - // update native caller to show what remote user has done. - void _handleCallState(CallState state) { - Logs().i('CallKeepManager::handleCallState: ${state.toString()}'); - switch (state) { - case CallState.kConnecting: - Logs().v('callkeep connecting'); - break; - case CallState.kConnected: - Logs().v('callkeep connected'); - if (!connected) { - callKeepManager.answer(call.callId); - } else { - callKeepManager.setMutedCall(call.callId, false); - callKeepManager.setOnHold(call.callId, false); - } - break; - case CallState.kEnded: - callKeepManager.hangup(call.callId); - break; - - case CallState.kFledgling: - case CallState.kInviteSent: - case CallState.kWaitLocalMedia: - case CallState.kCreateOffer: - case CallState.kCreateAnswer: - case CallState.kRinging: - case CallState.kEnding: - break; - } - } -} - -Map calls = {}; - -class CallKeepManager { - factory CallKeepManager() { - return _instance; - } - - CallKeepManager._internal() { - _callKeep = FlutterCallkeep(); - } - - static final CallKeepManager _instance = CallKeepManager._internal(); - - late FlutterCallkeep _callKeep; - - String get appName => 'FluffyChat'; - - Future get hasPhoneAccountEnabled async => - await _callKeep.hasPhoneAccount(); - - Map get alertOptions => { - 'alertTitle': 'Permissions required', - 'alertDescription': - 'Allow $appName to register as a calling account? This will allow calls to be handled by the native android dialer.', - 'cancelButton': 'Cancel', - 'okButton': 'ok', - // Required to get audio in background when using Android 11 - 'foregroundService': { - 'channelId': 'com.fluffy.fluffychat', - 'channelName': 'Foreground service for my app', - 'notificationTitle': '$appName is running on background', - 'notificationIcon': 'mipmap/ic_notification_launcher', - }, - 'additionalPermissions': [''], - }; - bool setupDone = false; - - Future showCallkitIncoming(CallSession call) async { - if (!setupDone) { - await _callKeep.setup( - null, - { - 'ios': { - 'appName': appName, - }, - 'android': alertOptions, - }, - backgroundMode: true, - ); - } - setupDone = true; - await displayIncomingCall(call); - call.onCallStateChanged.stream.listen((state) { - if (state == CallState.kEnded) { - _callKeep.endAllCalls(); - } - }); - call.onCallEventChanged.stream.listen( - (event) { - if (event == CallStateChange.kLocalHoldUnhold) { - Logs().i( - 'Call hold event: local ${call.localHold}, remote ${call.remoteOnHold}', - ); - } - }, - ); - } - - void removeCall(String? callUUID) { - calls.remove(callUUID); - } - - void addCall(String? callUUID, CallKeeper callKeeper) { - if (calls.containsKey(callUUID)) return; - calls[callUUID] = callKeeper; - } - - void setCallHeld(String? callUUID, bool? held) { - calls[callUUID]!.held = held; - } - - void setCallMuted(String? callUUID, bool? muted) { - calls[callUUID]!.muted = muted; - } - - void didDisplayIncomingCall(CallKeepDidDisplayIncomingCall event) { - final callUUID = event.callUUID; - final number = event.handle; - Logs().v('[displayIncomingCall] $callUUID number: $number'); - // addCall(callUUID, CallKeeper(this null)); - } - - void onPushKitToken(CallKeepPushKitToken event) { - Logs().v('[onPushKitToken] token => ${event.token}'); - } - - Future initialize() async { - _callKeep.on(CallKeepPerformAnswerCallAction(), answerCall); - _callKeep.on(CallKeepDidPerformDTMFAction(), didPerformDTMFAction); - - _callKeep.on(CallKeepDidToggleHoldAction(), didToggleHoldCallAction); - _callKeep.on( - CallKeepDidPerformSetMutedCallAction(), - didPerformSetMutedCallAction, - ); - _callKeep.on(CallKeepPerformEndCallAction(), endCall); - _callKeep.on(CallKeepPushKitToken(), onPushKitToken); - _callKeep.on(CallKeepDidDisplayIncomingCall(), didDisplayIncomingCall); - Logs().i('[VOIP] Initialized'); - } - - Future hangup(String callUUID) async { - await _callKeep.endCall(callUUID); - removeCall(callUUID); - } - - Future reject(String callUUID) async { - await _callKeep.rejectCall(callUUID); - } - - Future answer(String? callUUID) async { - final keeper = calls[callUUID]!; - if (!keeper.connected) { - await _callKeep.answerIncomingCall(callUUID!); - keeper.connected = true; - } - } - - Future setOnHold(String callUUID, bool held) async { - await _callKeep.setOnHold(callUUID, held); - setCallHeld(callUUID, held); - } - - Future setMutedCall(String callUUID, bool muted) async { - await _callKeep.setMutedCall(callUUID, muted); - setCallMuted(callUUID, muted); - } - - Future updateDisplay(String callUUID) async { - // Workaround because Android doesn't display well displayName, se we have to switch ... - if (isIOS) { - await _callKeep.updateDisplay( - callUUID, - displayName: 'New Name', - handle: callUUID, - ); - } else { - await _callKeep.updateDisplay( - callUUID, - displayName: callUUID, - handle: 'New Name', - ); - } - } - - Future displayIncomingCall(CallSession call) async { - final callKeeper = CallKeeper(this, call); - addCall(call.callId, callKeeper); - await _callKeep.displayIncomingCall( - call.callId, - '${call.room.getLocalizedDisplayname()} (FluffyChat)', - localizedCallerName: - '${call.room.getLocalizedDisplayname()} (FluffyChat)', - handleType: 'number', - hasVideo: call.type == CallType.kVideo, - ); - return callKeeper; - } - - Future checkoutPhoneAccountSetting(BuildContext context) async { - showDialog( - context: context, - barrierDismissible: true, - useRootNavigator: false, - builder: (_) => AlertDialog( - title: Text(L10n.of(context).callingPermissions), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - onTap: () => openCallingAccountsPage(context), - title: Text(L10n.of(context).callingAccount), - subtitle: Text(L10n.of(context).callingAccountDetails), - trailing: const Icon(Icons.phone), - ), - const Divider(), - ListTile( - onTap: () => FlutterForegroundTask.openSystemAlertWindowSettings( - forceOpen: true, - ), - title: Text(L10n.of(context).appearOnTop), - subtitle: Text(L10n.of(context).appearOnTopDetails), - trailing: const Icon(Icons.file_upload_rounded), - ), - const Divider(), - ListTile( - onTap: () => openAppSettings(), - title: Text(L10n.of(context).otherCallingPermissions), - trailing: const Icon(Icons.mic), - ), - ], - ), - ), - ); - } - - void openCallingAccountsPage(BuildContext context) async { - await _callKeep.setup(context, { - 'ios': { - 'appName': appName, - }, - 'android': alertOptions, - }); - final hasPhoneAccount = await _callKeep.hasPhoneAccount(); - Logs().e(hasPhoneAccount.toString()); - if (!hasPhoneAccount) { - await _callKeep.hasDefaultPhoneAccount(context, alertOptions); - } else { - await _callKeep.openPhoneAccounts(); - } - } - - /// CallActions. - Future answerCall(CallKeepPerformAnswerCallAction event) async { - final callUUID = event.callUUID; - final keeper = calls[event.callUUID]!; - if (!keeper.connected) { - Logs().e('answered'); - // Answer Call - keeper.call.answer(); - keeper.connected = true; - } - Timer(const Duration(seconds: 1), () { - _callKeep.setCurrentCallActive(callUUID!); - }); - } - - Future endCall(CallKeepPerformEndCallAction event) async { - final keeper = calls[event.callUUID]; - keeper?.call.hangup(reason: CallErrorCode.userHangup); - removeCall(event.callUUID); - } - - Future didPerformDTMFAction(CallKeepDidPerformDTMFAction event) async { - final keeper = calls[event.callUUID]!; - keeper.call.sendDTMF(event.digits!); - } - - Future didPerformSetMutedCallAction( - CallKeepDidPerformSetMutedCallAction event, - ) async { - final keeper = calls[event.callUUID]; - if (event.muted!) { - keeper!.call.setMicrophoneMuted(true); - } else { - keeper!.call.setMicrophoneMuted(false); - } - setCallMuted(event.callUUID, event.muted); - } - - Future didToggleHoldCallAction( - CallKeepDidToggleHoldAction event, - ) async { - final keeper = calls[event.callUUID]; - if (event.hold!) { - keeper!.call.setRemoteOnHold(true); - } else { - keeper!.call.setRemoteOnHold(false); - } - setCallHeld(event.callUUID, event.hold); - } -} diff --git a/lib/utils/voip_plugin.dart b/lib/utils/voip_plugin.dart index 6d0c06dcd..c5120d604 100644 --- a/lib/utils/voip_plugin.dart +++ b/lib/utils/voip_plugin.dart @@ -11,7 +11,6 @@ import 'package:webrtc_interface/webrtc_interface.dart' hide Navigator; import 'package:fluffychat/pages/chat_list/chat_list.dart'; import 'package:fluffychat/pages/dialer/dialer.dart'; import 'package:fluffychat/utils/platform_infos.dart'; -import '../../utils/voip/callkeep_manager.dart'; import '../../utils/voip/user_media_manager.dart'; import '../widgets/matrix.dart'; @@ -89,8 +88,7 @@ class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate { ]) => webrtc_impl.createPeerConnection(configuration, constraints); - Future get hasCallingAccount async => - kIsWeb ? false : await CallKeepManager().hasPhoneAccountEnabled; + Future get hasCallingAccount async => false; @override Future playRingtone() async { @@ -113,46 +111,21 @@ class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate { @override Future handleNewCall(CallSession call) async { if (PlatformInfos.isAndroid) { - // probably works on ios too - final hasCallingAccount = await CallKeepManager().hasPhoneAccountEnabled; - if (call.direction == CallDirection.kIncoming && - hasCallingAccount && - call.type == CallType.kVoice) { - ///Popup native telecom manager call UI for incoming call. - final callKeeper = CallKeeper(CallKeepManager(), call); - CallKeepManager().addCall(call.callId, callKeeper); - await CallKeepManager().showCallkitIncoming(call); - return; - } else { - try { - final wasForeground = await FlutterForegroundTask.isAppOnForeground; - - await matrix.store.setString( - 'wasForeground', - wasForeground == true ? 'true' : 'false', - ); - FlutterForegroundTask.setOnLockScreenVisibility(true); - FlutterForegroundTask.wakeUpScreen(); - FlutterForegroundTask.launchApp(); - } catch (e) { - Logs().e('VOIP foreground failed $e'); - } - // use fallback flutter call pages for outgoing and video calls. - addCallingOverlay(call.callId, call); - try { - if (!hasCallingAccount) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'No calling accounts found (used for native calls UI)', - ), - ), - ); - } - } catch (e) { - Logs().e('failed to show snackbar'); - } + try { + final wasForeground = await FlutterForegroundTask.isAppOnForeground; + + await matrix.store.setString( + 'wasForeground', + wasForeground == true ? 'true' : 'false', + ); + FlutterForegroundTask.setOnLockScreenVisibility(true); + FlutterForegroundTask.wakeUpScreen(); + FlutterForegroundTask.launchApp(); + } catch (e) { + Logs().e('VOIP foreground failed $e'); } + // use fallback flutter call pages for outgoing and video calls. + addCallingOverlay(call.callId, call); } else { addCallingOverlay(call.callId, call); } diff --git a/pubspec.lock b/pubspec.lock index 91ddbea71..9b950a3ea 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -110,14 +110,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" - callkeep: - dependency: "direct main" - description: - name: callkeep - sha256: "9e86e9632a603a61f7045c179ea5ca0ee4da0a49fc5f80c2fe09fb422b96d3c6" - url: "https://pub.dev" - source: hosted - version: "0.3.3" canonical_json: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 23572df3d..6e96eda57 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,7 +13,6 @@ dependencies: async: ^2.11.0 badges: ^3.1.2 blurhash_dart: ^1.2.1 - callkeep: ^0.3.2 chewie: ^1.8.1 collection: ^1.18.0 cross_file: ^0.3.4+2