1 /*
<lambda>null2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.example.testdiscoverservice
17 
18 import android.net.nsd.NsdManager
19 import android.net.nsd.NsdManager.ServiceInfoCallback
20 import android.net.nsd.NsdServiceInfo
21 import android.os.Bundle
22 import android.text.TextUtils
23 import android.util.Log
24 import android.widget.RadioGroup
25 import android.widget.TextView
26 import androidx.annotation.RequiresApi
27 import androidx.appcompat.app.AppCompatActivity
28 
29 private val TAG = DiscoverActivity::class.simpleName
30 
31 class DiscoverActivity : AppCompatActivity() {
32 
33     private val nsdManager by lazy { getSystemService(NsdManager::class.java) }
34     private val lblLog by lazy { findViewById<TextView>(R.id.lblMainActivity) }
35     private val radioGroupMode by lazy { findViewById<RadioGroup>(R.id.radioGroupMode) }
36     private val log = mutableListOf<String>()
37     private var discoveryListener: DiscoveryListener? = null
38     private var serviceInfoListener: WatchListener? = null
39     private var resolveListener: ResolveListener? = null
40 
41     @RequiresApi(34)
42     override fun onCreate(savedInstanceState: Bundle?) {
43         super.onCreate(savedInstanceState)
44         setContentView(R.layout.activity_main)
45 
46         radioGroupMode.setOnCheckedChangeListener { _, _ ->
47             stop()
48             startNsdManager()
49         }
50     }
51 
52     @RequiresApi(34)
53     override fun onStart() {
54         super.onStart()
55         startNsdManager()
56     }
57 
58     @RequiresApi(34)
59     private fun startNsdManager() {
60         when (radioGroupMode.checkedRadioButtonId) {
61             R.id.radioDiscover -> startDiscovery()
62             R.id.radioWatch -> startWatch()
63             R.id.radioResolve -> startResolve()
64         }
65     }
66 
67     private fun startDiscovery() {
68         log("Starting discovery")
69         discoveryListener = DiscoveryListener()
70         nsdManager.discoverServices("_nmt._tcp", NsdManager.PROTOCOL_DNS_SD, discoveryListener)
71     }
72 
73     @RequiresApi(34)
74     private fun startWatch() {
75         log("Starting watch")
76 
77         val serviceInfo = NsdServiceInfo().apply {
78             serviceName = "test_service"
79             serviceType = "_nmt._tcp"
80         }
81 
82         serviceInfoListener = WatchListener().also { listener ->
83             nsdManager.registerServiceInfoCallback(serviceInfo, { it.run() }, listener)
84         }
85     }
86 
87     private fun startResolve() {
88         log("Starting resolve")
89 
90         val serviceInfo = NsdServiceInfo().apply {
91             serviceName = "test_service"
92             serviceType = "_nmt._tcp"
93         }
94 
95         resolveListener = ResolveListener("Test1").also { listener ->
96             nsdManager.resolveService(serviceInfo, { it.run() }, listener)
97         }
98     }
99 
100     @RequiresApi(34)
101     override fun onStop() {
102         super.onStop()
103 
104         stop()
105     }
106 
107     @RequiresApi(34)
108     private fun stop() {
109         log("Stopping current operation")
110         discoveryListener?.let { nsdManager.stopServiceDiscovery(it) }
111         discoveryListener = null
112         serviceInfoListener?.let { nsdManager.unregisterServiceInfoCallback(it) }
113         serviceInfoListener = null
114         resolveListener?.let { nsdManager.stopServiceResolution(it) }
115         resolveListener = null
116     }
117 
118     private fun log(msg: String) {
119         runOnUiThread {
120             log.add(msg)
121             Log.i(TAG, msg)
122             lblLog.text = TextUtils.join("\n", log)
123         }
124     }
125 
126     inner class DiscoveryListener : NsdManager.DiscoveryListener {
127         override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) {
128             log("Start discovery failed for type $serviceType, error $errorCode")
129         }
130 
131         override fun onStopDiscoveryFailed(serviceType: String?, errorCode: Int) {
132             log("Stop discovery failed for type $serviceType, error $errorCode")
133         }
134 
135         override fun onDiscoveryStarted(serviceType: String?) {
136             log("Discovery started for type $serviceType")
137         }
138 
139         override fun onDiscoveryStopped(serviceType: String?) {
140             log("Discovery stopped for type $serviceType")
141         }
142 
143         override fun onServiceFound(serviceInfo: NsdServiceInfo?) {
144             log("Service found for type $serviceInfo")
145 
146         }
147 
148         override fun onServiceLost(serviceInfo: NsdServiceInfo?) {
149             log("Service lost for type $serviceInfo")
150         }
151     }
152 
153     inner class ResolveListener(private val name : String) : NsdManager.ResolveListener {
154         override fun onResolveFailed(serviceInfo: NsdServiceInfo?, errorCode: Int) {
155             log("listenerName $name Resolve failed for service $serviceInfo with code $errorCode")
156         }
157 
158         override fun onServiceResolved(serviceInfo: NsdServiceInfo?) {
159             log("listenerName $name Service resolved: $serviceInfo")
160         }
161     }
162 
163     @RequiresApi(34)
164     inner class WatchListener : ServiceInfoCallback {
165         override fun onServiceInfoCallbackRegistrationFailed(p0: Int) {}
166 
167         override fun onServiceUpdated(serviceInfo: NsdServiceInfo) {
168             log("Service updated: $serviceInfo")
169         }
170 
171         override fun onServiceLost() {
172             log("Watched service lost")
173         }
174 
175         override fun onServiceInfoCallbackUnregistered() {}
176     }
177 }