flutter_tele 2.0.5+105 copy "flutter_tele: ^2.0.5+105" to clipboard
flutter_tele: ^2.0.5+105 copied to clipboard

PlatformAndroid

Telecommunication module based on InCall and android.telecom for Flutter

example/lib/main.dart

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_tele/flutter_tele.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TeleEndpoint _endpoint = TeleEndpoint();
  String _status = 'Initializing...';
  List<TeleCall> _calls = [];
  TeleCall? _currentCall;
  String _phoneNumber = '';
  int _selectedSim = 1;
  bool _hasPermissions = false;
  bool _isDefaultDialer = false;
  bool _canSetDefaultDialer = false;

  @override
  void initState() {
    super.initState();
    _checkAndRequestPermissions();
    _setupEventListeners();
    _checkDialerStatus();
  }

  Future<void> _checkDialerStatus() async {
    setState(() {
      _status = 'Checking dialer status...';
    });
    
    final isDefault = await TeleDialer.isDefaultDialer();
    final canSet = await TeleDialer.canSetDefaultDialer();
    
    setState(() {
      _isDefaultDialer = isDefault;
      _canSetDefaultDialer = canSet;
      _status = 'Dialer status updated';
    });
  }

  Future<void> _checkAndRequestPermissions() async {
    setState(() {
      _status = 'Checking permissions...';
    });
    final hasPerms = await _endpoint.hasPermissions();
    setState(() {
      _hasPermissions = hasPerms;
    });
    if (!hasPerms) {
      setState(() {
        _status = 'Requesting permissions...';
      });
      final granted = await _endpoint.requestPermissions();
      setState(() {
        _hasPermissions = granted;
        _status = granted ? 'Permissions granted' : 'Permissions denied';
      });
      if (granted) {
        _initializeTelephony();
      }
    } else {
      _initializeTelephony();
    }
  }

  Future<void> _initializeTelephony() async {
    try {
      setState(() {
        _status = 'Starting telephony service...';
      });

      final result = await _endpoint.start({
        'ReplaceDialer': _isDefaultDialer,
        'Permissions': false,
      });

      setState(() {
        _status = 'Telephony service started successfully';
        _calls = List<TeleCall>.from(result['calls'] ?? []);
      });

      print('Initial state: $result');
    } catch (e) {
      setState(() {
        _status = 'Error starting telephony service: $e';
      });
      print('Error initializing telephony: $e');
    }
  }

  void _setupEventListeners() {
    _endpoint.on('call_received').listen((event) {
      print('Call received: $event');
      setState(() {
        _status = 'Incoming call received';
        if (event is Map) {
          final eventMap = event.map((k, v) => MapEntry(k.toString(), v));
          _currentCall = TeleCall.fromMap(eventMap);
          _calls.add(_currentCall!);
        }
      });
    });

    _endpoint.on('call_changed').listen((event) {
      print('Call changed: $event');
      setState(() {
        _status = 'Call state changed';
        if (event is Map) {
          final eventMap = event.map((k, v) => MapEntry(k.toString(), v));
          final updatedCall = TeleCall.fromMap(eventMap);
          final index = _calls.indexWhere((call) => call.id == updatedCall.id);
          if (index != -1) {
            _calls[index] = updatedCall;
            if (_currentCall?.id == updatedCall.id) {
              _currentCall = updatedCall;
            }
          }
        }
      });
    });

    _endpoint.on('call_terminated').listen((event) {
      print('Call terminated: $event');
      setState(() {
        _status = 'Call terminated';
        if (event is Map) {
          final eventMap = event.map((k, v) => MapEntry(k.toString(), v));
          final terminatedCall = TeleCall.fromMap(eventMap);
          _calls.removeWhere((call) => call.id == terminatedCall.id);
          if (_currentCall?.id == terminatedCall.id) {
            _currentCall = null;
          }
        }
      });
    });

    _endpoint.on('connectivity_changed').listen((event) {
      print('Connectivity changed: $event');
      setState(() {
        _status = 'Connectivity changed: $event';
      });
    });
  }

  Future<void> _makeCall() async {
    if (_phoneNumber.isEmpty) {
      setState(() {
        _status = 'Please enter a phone number';
      });
      return;
    }

    try {
      setState(() {
        _status = 'Making call...';
      });

      final call = await _endpoint.makeCall(
        _selectedSim,
        _phoneNumber,
        null, // callSettings
        null, // msgData
      );

      setState(() {
        _currentCall = call;
        _calls.add(call);
        _status = 'Call initiated';
      });

      print('Call made: $call');
    } catch (e) {
      setState(() {
        _status = 'Error making call: $e';
      });
      print('Error making call: $e');
    }
  }

  Future<void> _answerCall() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to answer';
      });
      return;
    }

    try {
      await _endpoint.answerCall(_currentCall!);
      setState(() {
        _status = 'Call answered';
      });
    } catch (e) {
      setState(() {
        _status = 'Error answering call: $e';
      });
      print('Error answering call: $e');
    }
  }

  Future<void> _hangupCall() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to hangup';
      });
      return;
    }

    try {
      await _endpoint.hangupCall(_currentCall!);
      setState(() {
        _status = 'Call hung up';
        _currentCall = null;
      });
    } catch (e) {
      setState(() {
        _status = 'Error hanging up call: $e';
      });
      print('Error hanging up call: $e');
    }
  }

  Future<void> _declineCall() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to decline';
      });
      return;
    }

    try {
      await _endpoint.declineCall(_currentCall!);
      setState(() {
        _status = 'Call declined';
        _currentCall = null;
      });
    } catch (e) {
      setState(() {
        _status = 'Error declining call: $e';
      });
      print('Error declining call: $e');
    }
  }

  Future<void> _muteCall() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to mute';
      });
      return;
    }

    try {
      await _endpoint.muteCall(_currentCall!);
      setState(() {
        _status = 'Call muted';
      });
    } catch (e) {
      setState(() {
        _status = 'Error muting call: $e';
      });
      print('Error muting call: $e');
    }
  }

  Future<void> _unMuteCall() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to unmute';
      });
      return;
    }

    try {
      await _endpoint.unMuteCall(_currentCall!);
      setState(() {
        _status = 'Call unmuted';
      });
    } catch (e) {
      setState(() {
        _status = 'Error unmuting call: $e';
      });
      print('Error unmuting call: $e');
    }
  }

  Future<void> _useSpeaker() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to use speaker';
      });
      return;
    }

    try {
      await _endpoint.useSpeaker(_currentCall!);
      setState(() {
        _status = 'Speaker enabled';
      });
    } catch (e) {
      setState(() {
        _status = 'Error using speaker: $e';
      });
      print('Error using speaker: $e');
    }
  }

  Future<void> _useEarpiece() async {
    if (_currentCall == null) {
      setState(() {
        _status = 'No call to use earpiece';
      });
      return;
    }

    try {
      await _endpoint.useEarpiece(_currentCall!);
      setState(() {
        _status = 'Earpiece enabled';
      });
    } catch (e) {
      setState(() {
        _status = 'Error using earpiece: $e';
      });
      print('Error using earpiece: $e');
    }
  }

  Future<void> _setDefaultDialer() async {
    try {
      setState(() {
        _status = 'Setting as default dialer...';
      });
      
      final success = await TeleDialer.setDefaultDialer();
      
      if (success) {
        setState(() {
          _status = 'Successfully set as default dialer';
          _isDefaultDialer = true;
        });
        
        // Verify that we actually became the default dialer
        await Future.delayed(const Duration(seconds: 2)); // Give system time to update
        final isActuallyDefault = await TeleDialer.isDefaultDialer();
        
        setState(() {
          _isDefaultDialer = isActuallyDefault;
          if (isActuallyDefault) {
            _status = 'Successfully set as default dialer (verified)';
          } else {
            _status = 'Set as default dialer but verification failed - user may have cancelled';
          }
        });
      } else {
        setState(() {
          _status = 'Failed to set as default dialer';
        });
      }
    } catch (e) {
      setState(() {
        _status = 'Error setting default dialer: $e';
      });
      print('Error setting default dialer: $e');
    }
  }

  @override
  void dispose() {
    _endpoint.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Tele Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Tele Example'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Status: $_status',
                        style: Theme.of(context).textTheme.titleMedium,
                      ),
                      const SizedBox(height: 8),
                      Row(
                        children: [
                          Text('Permissions: ${_hasPermissions ? 'Granted' : 'Not granted'}'),
                          const SizedBox(width: 8),
                          ElevatedButton(
                            onPressed: _checkAndRequestPermissions,
                            child: const Text('Check/Request Permissions'),
                          ),
                        ],
                      ),
                      const SizedBox(height: 16),
                      Card(
                        child: Padding(
                          padding: const EdgeInsets.all(12.0),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'Default Dialer Status',
                                style: Theme.of(context).textTheme.titleLarge,
                              ),
                              const SizedBox(height: 8),
                              Text(
                                _isDefaultDialer ? 'This app is the default dialer' : 'This app is NOT the default dialer',
                                style: Theme.of(context).textTheme.bodyLarge,
                                textAlign: TextAlign.center,
                              ),
                              const SizedBox(height: 8),
                              Text(
                                'Can Set as Default',
                                style: Theme.of(context).textTheme.titleLarge,
                              ),
                              const SizedBox(height: 8),
                              Text(
                                _canSetDefaultDialer ? 'This app can be set as default dialer' : 'This app cannot be set as default dialer',
                                style: Theme.of(context).textTheme.bodyLarge,
                                textAlign: TextAlign.center,
                              ),
                              const SizedBox(height: 16),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                                children: [
                                  if (_canSetDefaultDialer && !_isDefaultDialer)
                                    ElevatedButton(
                                      onPressed: _setDefaultDialer,
                                      child: const Text('Set as Default Dialer'),
                                    ),
                                  ElevatedButton(
                                    onPressed: _checkDialerStatus,
                                    child: const Text('Refresh Status'),
                                  ),
                                ],
                              ),
                              const SizedBox(height: 8),
                              Text(
                                'Note: Setting as default dialer will open the system settings dialog.',
                                style: Theme.of(context).textTheme.bodySmall,
                                textAlign: TextAlign.center,
                              ),
                            ],
                          ),
                        ),
                      ),
                      const SizedBox(height: 16),
                      TextField(
                        decoration: const InputDecoration(
                          labelText: 'Phone Number',
                          border: OutlineInputBorder(),
                        ),
                        keyboardType: TextInputType.phone,
                        onChanged: (value) {
                          setState(() {
                            _phoneNumber = value;
                          });
                        },
                      ),
                      const SizedBox(height: 8),
                      Row(
                        children: [
                          const Text('SIM: '),
                          DropdownButton<int>(
                            value: _selectedSim,
                            items: const [
                              DropdownMenuItem(value: 1, child: Text('SIM 1')),
                              DropdownMenuItem(value: 2, child: Text('SIM 2')),
                            ],
                            onChanged: (value) {
                              setState(() {
                                _selectedSim = value ?? 1;
                              });
                            },
                          ),
                        ],
                      ),
                      const SizedBox(height: 16),
                      ElevatedButton(
                        onPressed: _makeCall,
                        child: const Text('Make Call'),
                      ),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 16),
              if (_currentCall != null) ...[
                Card(
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Current Call',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        const SizedBox(height: 8),
                        Text('ID: ${_currentCall!.id}'),
                        Text('State: ${_currentCall!.state}'),
                        Text('Remote: ${_currentCall!.remoteNumber ?? 'Unknown'}'),
                        const SizedBox(height: 16),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            ElevatedButton(
                              onPressed: _answerCall,
                              child: const Text('Answer'),
                            ),
                            ElevatedButton(
                              onPressed: _hangupCall,
                              child: const Text('Hangup'),
                            ),
                            ElevatedButton(
                              onPressed: _declineCall,
                              child: const Text('Decline'),
                            ),
                          ],
                        ),
                        const SizedBox(height: 8),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            ElevatedButton(
                              onPressed: _muteCall,
                              child: const Text('Mute'),
                            ),
                            ElevatedButton(
                              onPressed: _unMuteCall,
                              child: const Text('Unmute'),
                            ),
                          ],
                        ),
                        const SizedBox(height: 8),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            ElevatedButton(
                              onPressed: _useSpeaker,
                              child: const Text('Speaker'),
                            ),
                            ElevatedButton(
                              onPressed: _useEarpiece,
                              child: const Text('Earpiece'),
                            ),
                          ],
                        ),
                      ],
                    ),
                  ),
                ),
              ],
              const SizedBox(height: 16),
              Expanded(
                child: Card(
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'All Calls (${_calls.length})',
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        const SizedBox(height: 8),
                        Expanded(
                          child: ListView.builder(
                            itemCount: _calls.length,
                            itemBuilder: (context, index) {
                              final call = _calls[index];
                              return ListTile(
                                title: Text('Call ${call.id}'),
                                subtitle: Text('${call.state} - ${call.remoteNumber ?? 'Unknown'}'),
                                trailing: Text(call.getFormattedTotalDuration()),
                              );
                            },
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
150
points
0
downloads

Publisher

unverified uploader

Weekly Downloads

Telecommunication module based on InCall and android.telecom for Flutter

Homepage

Documentation

API reference

License

unknown (license)

Dependencies

flutter, flutter_dialer, plugin_platform_interface

More

Packages that depend on flutter_tele

Packages that implement flutter_tele