Compare commits

...

1 Commits

Author SHA1 Message Date
5975977a52 Trying to get audio (DON'T COMPILE)
All checks were successful
/ mirror (push) Successful in 4s
2025-01-17 14:40:02 +02:00
10 changed files with 274 additions and 5 deletions

View File

@ -24,7 +24,7 @@ android {
applicationId = "com.example.dialer" applicationId = "com.example.dialer"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = 23
targetSdk = flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName

View File

@ -5,6 +5,9 @@
<uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS" /> <uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS" />
<uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS" /> <uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application

View File

@ -2,3 +2,4 @@ org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryErro
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
dev.steenbakker.mobile_scanner.useUnbundled=true dev.steenbakker.mobile_scanner.useUnbundled=true
org.gradle.java.home=/usr/lib/jvm/java-17-openjdk-amd64

View File

@ -3,6 +3,10 @@ import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../widgets/contact_service.dart'; import '../../widgets/contact_service.dart';
import '../contacts/widgets/add_contact_button.dart'; import '../contacts/widgets/add_contact_button.dart';
import '../../services/audio_handler.dart';
import '../../widgets/listen_replay_button.dart';
import '../../widgets/encrypt_audio_button.dart';
import 'package:permission_handler/permission_handler.dart';
class CompositionPage extends StatefulWidget { class CompositionPage extends StatefulWidget {
const CompositionPage({super.key}); const CompositionPage({super.key});
@ -17,12 +21,32 @@ class _CompositionPageState extends State<CompositionPage> {
List<Contact> _filteredContacts = []; List<Contact> _filteredContacts = [];
final ContactService _contactService = ContactService(); final ContactService _contactService = ContactService();
// Initialize AudioHandler
final AudioHandler _audioHandler = AudioHandler();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_requestPermissions();
_fetchContacts(); _fetchContacts();
} }
Future<void> _requestPermissions() async {
var statuses = await [
Permission.microphone,
Permission.contacts,
Permission.storage,
].request();
if (statuses[Permission.microphone] != PermissionStatus.granted ||
statuses[Permission.contacts] != PermissionStatus.granted ||
statuses[Permission.storage] != PermissionStatus.granted) {
// Handle permission denial
// For simplicity, just print a message
print('Permissions not granted');
}
}
Future<void> _fetchContacts() async { Future<void> _fetchContacts() async {
_allContacts = await _contactService.fetchContacts(); _allContacts = await _contactService.fetchContacts();
_filteredContacts = _allContacts; _filteredContacts = _allContacts;
@ -85,6 +109,12 @@ class _CompositionPageState extends State<CompositionPage> {
} }
} }
@override
void dispose() {
_audioHandler.stopListening();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -268,6 +298,21 @@ class _CompositionPageState extends State<CompositionPage> {
}, },
), ),
), ),
// New Buttons: Listen/Replay and Encrypt
Positioned(
bottom: 80.0, // Adjust as needed to position above AddContactButton
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ListenReplayButton(audioHandler: _audioHandler),
const SizedBox(width: 20),
EncryptAudioButton(audioHandler: _audioHandler),
],
),
),
], ],
), ),
); );

View File

@ -0,0 +1,111 @@
// lib/services/audio_handler.dart
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter_audio_capture/flutter_audio_capture.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class AudioHandler {
final FlutterAudioCapture _audioCapture = FlutterAudioCapture();
final FlutterSecureStorage _secureStorage = FlutterSecureStorage();
StreamController<Uint8List> _audioStreamController = StreamController.broadcast();
Timer? _delayTimer;
final int delaySeconds = 3;
// Encryption variables
encrypt.Encrypter? _encrypter;
encrypt.Key? _key;
bool _isEncryptionEnabled = false;
// Buffer for delay
List<Uint8List> _buffer = [];
// Constructor
AudioHandler();
// Start listening to the microphone
Future<void> startListening() async {
await _audioCapture.start(_onAudioData, _onError, sampleRate: 44100, bufferSize: 3000);
// Initialize the delay timer
_delayTimer = Timer.periodic(Duration(seconds: delaySeconds), (_) {
if (_buffer.isNotEmpty) {
// Replay the audio
Uint8List replayData = _buffer.removeAt(0);
_audioStreamController.add(replayData);
}
});
}
// Stop listening
Future<void> stopListening() async {
await _audioCapture.stop();
_delayTimer?.cancel();
_buffer.clear();
}
// Stream for UI to listen and replay audio
Stream<Uint8List> get audioStream => _audioStreamController.stream;
// Callback for audio data
void _onAudioData(dynamic obj) async {
Uint8List data = Uint8List.fromList(obj.cast<int>());
// Encrypt the data if encryption is enabled
if (_isEncryptionEnabled && _encrypter != null) {
final iv = encrypt.IV.fromSecureRandom(12); // Use a proper IV in production
final encrypted = _encrypter!.encryptBytes(data, iv: iv);
data = encrypted.bytes;
}
// Add data to buffer for delayed replay
_buffer.add(data);
// Optionally, you can handle encrypted data here
// For example, send it over the network or save to a file
}
// Error handling
void _onError(Object e) {
print('Audio Capture Error: $e');
}
// Enable encryption
Future<void> enableEncryption() async {
if (_isEncryptionEnabled) return;
// Check if key exists
String? storedKey = await _secureStorage.read(key: 'encryption_key');
if (storedKey == null) {
// Generate a new key
final newKey = _generateSecureKey();
await _secureStorage.write(key: 'encryption_key', value: newKey);
_key = encrypt.Key.fromUtf8(newKey);
} else {
_key = encrypt.Key.fromUtf8(storedKey);
}
_encrypter = encrypt.Encrypter(
encrypt.AES(
_key!,
mode: encrypt.AESMode.gcm,
padding: null,
),
);
_isEncryptionEnabled = true;
}
// Disable encryption
void disableEncryption() {
_encrypter = null;
_isEncryptionEnabled = false;
}
// Generate a secure key
String _generateSecureKey() {
// Implement a secure random key generator
// For demonstration, using a fixed key (DO NOT use in production)
return 'my32lengthsupersecretnooneknows1'; // 32 chars for AES-256
}
}

View File

@ -0,0 +1,40 @@
// lib/widgets/encrypt_audio_button.dart
import 'package:flutter/material.dart';
import '../services/audio_handler.dart';
class EncryptAudioButton extends StatefulWidget {
final AudioHandler audioHandler;
const EncryptAudioButton({Key? key, required this.audioHandler}) : super(key: key);
@override
_EncryptAudioButtonState createState() => _EncryptAudioButtonState();
}
class _EncryptAudioButtonState extends State<EncryptAudioButton> {
bool _isEncrypted = false;
void _toggleEncryption() {
setState(() {
_isEncrypted = !_isEncrypted;
if (_isEncrypted) {
widget.audioHandler.enableEncryption();
} else {
widget.audioHandler.disableEncryption();
}
});
}
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(
_isEncrypted ? Icons.lock : Icons.lock_open,
color: Colors.blueAccent,
),
onPressed: _toggleEncryption,
tooltip: _isEncrypted ? 'Disable Encryption' : 'Enable Encryption',
);
}
}

View File

@ -0,0 +1,65 @@
// lib/widgets/listen_replay_button.dart
import 'package:flutter/material.dart';
import '../services/audio_handler.dart';
import 'package:audioplayers/audioplayers.dart';
class ListenReplayButton extends StatefulWidget {
final AudioHandler audioHandler;
const ListenReplayButton({Key? key, required this.audioHandler}) : super(key: key);
@override
_ListenReplayButtonState createState() => _ListenReplayButtonState();
}
class _ListenReplayButtonState extends State<ListenReplayButton> {
bool _isListening = false;
final AudioPlayer _audioPlayer = AudioPlayer();
void _toggleListening() async {
if (_isListening) {
await widget.audioHandler.stopListening();
} else {
await widget.audioHandler.startListening();
// Listen to the audio stream and replay it
widget.audioHandler.audioStream.listen((data) async {
// Convert Uint8List to a playable format
// For simplicity, we'll write to a temporary file and play it
// In production, consider using a more efficient method
String filePath = '/tmp/temp_audio.aac'; // Adjust path as needed
// Use path_provider to get a valid directory
// Add dependency: path_provider: ^2.0.11
// Alternatively, use a package that allows in-memory playback
// Placeholder: Play directly from bytes is not supported by audioplayers
// You may need to implement native playback or use another package
// For demonstration, we'll skip actual playback
print('Replaying audio data: ${data.length} bytes');
});
}
setState(() {
_isListening = !_isListening;
});
}
@override
void dispose() {
_audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(
_isListening ? Icons.stop : Icons.mic,
color: Colors.orangeAccent,
),
onPressed: _toggleListening,
tooltip: _isListening ? 'Stop Listening' : 'Listen and Replay',
);
}
}

View File

@ -27,7 +27,7 @@ android {
defaultConfig { defaultConfig {
targetSdkVersion 33 targetSdkVersion 33
minSdkVersion 21 minSdkVersion 23
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
lintOptions { lintOptions {

View File

@ -30,7 +30,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.example.mobile_number_example" applicationId "com.example.mobile_number_example"
minSdkVersion 21 minSdkVersion 23
targetSdkVersion 33 targetSdkVersion 33
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

View File

@ -41,7 +41,7 @@ dependencies:
cached_network_image: ^3.2.3 # For caching contact images cached_network_image: ^3.2.3 # For caching contact images
qr_flutter: ^4.1.0 qr_flutter: ^4.1.0
android_intent_plus: ^5.2.0 android_intent_plus: ^5.2.0
camera: ^0.10.0+2 camera: ^0.11.0+2
mobile_scanner: ^6.0.2 mobile_scanner: ^6.0.2
pretty_qr_code: ^3.3.0 pretty_qr_code: ^3.3.0
pointycastle: ^3.4.0 pointycastle: ^3.4.0
@ -49,10 +49,14 @@ dependencies:
asn1lib: ^1.0.0 asn1lib: ^1.0.0
intl_utils: ^2.0.7 intl_utils: ^2.0.7
url_launcher: ^6.3.1 url_launcher: ^6.3.1
flutter_secure_storage: ^9.0.0 flutter_secure_storage: ^10.0.0-beta.4
mobile_number: mobile_number:
path: packages/mobile_number path: packages/mobile_number
flutter_audio_capture: ^1.1.8
encrypt: ^5.0.3
audioplayers: ^6.1.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter