Line data Source code
1 : import 'dart:convert';
2 : import 'package:flutter/foundation.dart';
3 : import 'package:flutter/services.dart';
4 : import 'package:flutter_chrome_cast/_discovery_manager/discovery_manager_platform_interface.dart';
5 : import 'package:flutter_chrome_cast/entities/cast_device.dart';
6 : import 'package:flutter_chrome_cast/models/android/cast_device.dart';
7 : import 'package:rxdart/subjects.dart';
8 :
9 : /// Android-specific implementation of the Google Cast discovery manager.
10 : ///
11 : /// This class handles the discovery of Google Cast devices on Android platform
12 : /// using method channels to communicate with the native Android implementation.
13 : class GoogleCastDiscoveryManagerMethodChannelAndroid
14 : implements GoogleCastDiscoveryManagerPlatformInterface {
15 : /// Creates a new instance of the Android discovery manager.
16 : ///
17 : /// Sets up the method call handler to receive updates from the native side.
18 2 : GoogleCastDiscoveryManagerMethodChannelAndroid() {
19 6 : _channel.setMethodCallHandler(_onMethodCallHandler);
20 : }
21 :
22 : final _channel =
23 : const MethodChannel('com.felnanuke.google_cast.discovery_manager');
24 :
25 : final _devicesStreamController = BehaviorSubject<List<GoogleCastDevice>>()
26 : ..add([]);
27 :
28 1 : @override
29 2 : List<GoogleCastDevice> get devices => _devicesStreamController.value;
30 :
31 1 : @override
32 : Stream<List<GoogleCastDevice>> get devicesStream =>
33 2 : _devicesStreamController.stream;
34 :
35 1 : @override
36 : Future<bool> isDiscoveryActiveForDeviceCategory(String deviceCategory) {
37 1 : throw UnimplementedError('IOS Only');
38 : }
39 :
40 1 : @override
41 : Future<void> startDiscovery() async {
42 2 : _channel.invokeMethod('startDiscovery');
43 : return;
44 : }
45 :
46 1 : @override
47 : Future<void> stopDiscovery() async {
48 2 : _channel.invokeMethod('stopDiscovery');
49 : return;
50 : }
51 :
52 1 : Future _onMethodCallHandler(MethodCall call) async {
53 1 : switch (call.method) {
54 1 : case 'onDevicesChanged':
55 2 : return _onDevicesChanged(call.arguments);
56 :
57 : default:
58 : }
59 : }
60 :
61 1 : void _onDevicesChanged(dynamic arguments) {
62 : try {
63 : arguments as String;
64 1 : final list = jsonDecode(arguments);
65 1 : final listMap = List.from(list);
66 1 : final devices = GoogleCastAndroidDevices.fromMap(listMap);
67 :
68 : if (kDebugMode) {
69 3 : print('Received ${devices.length} devices from native');
70 2 : for (final device in devices) {
71 1 : print(
72 4 : 'Device: ${device.deviceID} - ${device.friendlyName} (${device.modelName})');
73 : }
74 : }
75 :
76 : // Enhanced deduplication: remove devices with same name and model
77 1 : final Map<String, GoogleCastDevice> uniqueDevices = {};
78 2 : for (final device in devices) {
79 3 : final key = '${device.friendlyName}_${device.modelName}';
80 1 : if (!uniqueDevices.containsKey(key)) {
81 1 : uniqueDevices[key] = device;
82 : if (kDebugMode) {
83 2 : print('Added unique device with key: $key');
84 : }
85 : } else {
86 : if (kDebugMode) {
87 2 : print('Skipped duplicate device with key: $key');
88 : }
89 : }
90 : }
91 :
92 : if (kDebugMode) {
93 1 : print(
94 2 : 'Final device count after deduplication: ${uniqueDevices.length}');
95 : }
96 4 : _devicesStreamController.add(uniqueDevices.values.toList());
97 : } catch (e) {
98 : rethrow;
99 : }
100 : }
101 : }
|