|
| 1 | +/* |
| 2 | + * Copyright (C) 2014-2024 Arpit Khurana <[email protected]>, Vishal Nehra <[email protected]>, |
| 3 | + * Emmanuel Messulam<[email protected]>, Raymond Lai <airwave209gt at gmail.com> and Contributors. |
| 4 | + * |
| 5 | + * This file is part of Amaze File Manager. |
| 6 | + * |
| 7 | + * Amaze File Manager is free software: you can redistribute it and/or modify |
| 8 | + * it under the terms of the GNU General Public License as published by |
| 9 | + * the Free Software Foundation, either version 3 of the License, or |
| 10 | + * (at your option) any later version. |
| 11 | + * |
| 12 | + * This program is distributed in the hope that it will be useful, |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | + * GNU General Public License for more details. |
| 16 | + * |
| 17 | + * You should have received a copy of the GNU General Public License |
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | + */ |
| 20 | + |
| 21 | +package com.amaze.filemanager.utils.smb |
| 22 | + |
| 23 | +import android.content.Context.NSD_SERVICE |
| 24 | +import android.content.Context.WIFI_SERVICE |
| 25 | +import android.net.nsd.NsdManager |
| 26 | +import android.net.nsd.NsdServiceInfo |
| 27 | +import android.net.wifi.WifiManager |
| 28 | +import android.os.Build.VERSION.SDK_INT |
| 29 | +import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE |
| 30 | +import com.amaze.filemanager.application.AppConfig |
| 31 | +import com.amaze.filemanager.utils.ComputerParcelable |
| 32 | +import org.slf4j.Logger |
| 33 | +import org.slf4j.LoggerFactory |
| 34 | + |
| 35 | +/** |
| 36 | + * [SmbDeviceScannerObservable.DiscoverDeviceStrategy] implementation using Android's |
| 37 | + * [NsdManager] to discover SMB devices using mDNS/Bonjour/ZeroConf. |
| 38 | + * |
| 39 | + * @see SmbDeviceScannerObservable |
| 40 | + * @see NsdManager |
| 41 | + * |
| 42 | + */ |
| 43 | +class NsdManagerDiscoverDeviceStrategy : SmbDeviceScannerObservable.DiscoverDeviceStrategy { |
| 44 | + companion object { |
| 45 | + internal const val SERVICE_TYPE_SMB = "_smb._tcp." |
| 46 | + private val logger: Logger = |
| 47 | + LoggerFactory.getLogger(NsdManagerDiscoverDeviceStrategy::class.java) |
| 48 | + } |
| 49 | + |
| 50 | + private val wifiManager: WifiManager = |
| 51 | + AppConfig.getInstance().applicationContext.getSystemService(WIFI_SERVICE) as WifiManager |
| 52 | + private val nsdManager: NsdManager = |
| 53 | + AppConfig.getInstance().applicationContext.getSystemService(NSD_SERVICE) as NsdManager |
| 54 | + |
| 55 | + private var multicastLock: WifiManager.MulticastLock? = null |
| 56 | + private var discoveryListener: NsdManager.DiscoveryListener? = null |
| 57 | + |
| 58 | + override fun discoverDevices(callback: (ComputerParcelable) -> Unit) { |
| 59 | + multicastLock = |
| 60 | + wifiManager.createMulticastLock("smb_mdns_discovery").apply { |
| 61 | + setReferenceCounted(true) |
| 62 | + } |
| 63 | + multicastLock?.acquire() |
| 64 | + discoveryListener = createDiscoveryListener(callback) |
| 65 | + nsdManager.discoverServices( |
| 66 | + SERVICE_TYPE_SMB, |
| 67 | + NsdManager.PROTOCOL_DNS_SD, |
| 68 | + discoveryListener, |
| 69 | + ) |
| 70 | + } |
| 71 | + |
| 72 | + override fun onCancel() { |
| 73 | + discoveryListener?.let { |
| 74 | + nsdManager.stopServiceDiscovery(it) |
| 75 | + discoveryListener = null |
| 76 | + } |
| 77 | + multicastLock?.let { |
| 78 | + if (it.isHeld) { |
| 79 | + it.release() |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + /** |
| 85 | + * Creates a new [NsdManager.DiscoveryListener] to handle service discovery events. |
| 86 | + * |
| 87 | + * For backward compatibility, uses [NsdManager.ResolveListener] to resolve services |
| 88 | + * and perform the callback. |
| 89 | + */ |
| 90 | + private fun createDiscoveryListener(callback: (ComputerParcelable) -> Unit): NsdManager.DiscoveryListener { |
| 91 | + return object : NsdManager.DiscoveryListener { |
| 92 | + override fun onServiceFound(serviceInfo: NsdServiceInfo) { |
| 93 | + @Suppress("DEPRECATION") |
| 94 | + nsdManager.resolveService( |
| 95 | + serviceInfo, |
| 96 | + object : NsdManager.ResolveListener { |
| 97 | + override fun onServiceResolved(resolvedServiceInfo: NsdServiceInfo) { |
| 98 | + val host = |
| 99 | + if (SDK_INT >= UPSIDE_DOWN_CAKE) { |
| 100 | + resolvedServiceInfo.hostAddresses.firstOrNull() |
| 101 | + } else { |
| 102 | + resolvedServiceInfo.host |
| 103 | + } |
| 104 | + if (host != null && host.hostAddress?.isNotEmpty() == true) { |
| 105 | + val computer = |
| 106 | + ComputerParcelable( |
| 107 | + name = resolvedServiceInfo.serviceName, |
| 108 | + addr = host.hostAddress!!, |
| 109 | + ) |
| 110 | + callback(computer) |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + override fun onResolveFailed( |
| 115 | + serviceInfo: NsdServiceInfo?, |
| 116 | + errorCode: Int, |
| 117 | + ) { |
| 118 | + logger.error( |
| 119 | + "Service resolve failed: ${serviceInfo?.serviceName} with error code: $errorCode", |
| 120 | + ) |
| 121 | + } |
| 122 | + }, |
| 123 | + ) |
| 124 | + } |
| 125 | + |
| 126 | + override fun onServiceLost(serviceInfo: NsdServiceInfo?) { |
| 127 | + logger.debug("Service lost: ${serviceInfo?.serviceName}") |
| 128 | + } |
| 129 | + |
| 130 | + override fun onStartDiscoveryFailed( |
| 131 | + serviceType: String, |
| 132 | + errorCode: Int, |
| 133 | + ) { |
| 134 | + logger.error("Service discovery start failed: $serviceType with error code: $errorCode") |
| 135 | + nsdManager.stopServiceDiscovery(this) |
| 136 | + } |
| 137 | + |
| 138 | + override fun onStopDiscoveryFailed( |
| 139 | + serviceType: String, |
| 140 | + errorCode: Int, |
| 141 | + ) { |
| 142 | + logger.debug("Service discovery stop failed: $serviceType with error code: $errorCode") |
| 143 | + nsdManager.stopServiceDiscovery(this) |
| 144 | + } |
| 145 | + |
| 146 | + override fun onDiscoveryStarted(serviceType: String?) = logger.debug("Service discovery started: $serviceType") |
| 147 | + |
| 148 | + override fun onDiscoveryStopped(serviceType: String?) = logger.debug("Service discovery stopped: $serviceType") |
| 149 | + } |
| 150 | + } |
| 151 | +} |
0 commit comments