• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Using Wi-Fi Direct for Service Discovery
2parent.title=Connecting Devices Wirelessly
3parent.link=index.html
4
5trainingnavtop=true
6
7@jd:body
8
9<div id="tb-wrapper">
10  <div id="tb">
11    <h2>This lesson teaches you to</h2>
12    <ol>
13      <li><a href="#manifest">Set Up the Manifest</a></li>
14      <li><a href="#register">Add a Local Service</a></li>
15      <li><a href="#discover">Discover Nearby Services</a></li>
16    </ol>
17    <!--
18    <h2>You should also read</h2>
19    <ul>
20      <li><a href="#"></a></li>
21    </ul>
22    -->
23  </div>
24</div>
25
26<p>The first lesson in this class, <a href="nsd.html">Using Network Service
27  Discovery</a>, showed you
28how to discover services that are connected to a local network. However, using
29Wi-Fi Direct&trad; Service Discovery allows you to discover the services of nearby devices directly,
30without being connected to a network.  You can also advertise the services
31running on your device.  These capabilities help you communicate between apps,
32even when no local network or hotspot is available.</p>
33<p>While this set of APIs is similar in purpose to the Network Service Discovery
34APIs outlined in a previous lesson, implementing them in code is very different.
35This lesson shows you how to discover services available from other devices,
36using Wi-Fi Direct&trade;. The lesson assumes that you're already familiar with the
37<a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi Direct</a> API.</p>
38
39
40<h2 id="manifest">Set Up the Manifest</h2>
41<p>In order to use Wi-Fi Direct, add the {@link
42android.Manifest.permission#CHANGE_WIFI_STATE}, {@link
43android.Manifest.permission#ACCESS_WIFI_STATE},
44and {@link android.Manifest.permission#INTERNET}
45permissions to your manifest.  Even though Wi-Fi Direct doesn't require an
46Internet connection, it uses standard Java sockets, and using these in Android
47requires the requested permissions.</p>
48
49<pre>
50&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
51    package="com.example.android.nsdchat"
52    ...
53
54    &lt;uses-permission
55        android:required="true"
56        android:name="android.permission.ACCESS_WIFI_STATE"/&gt;
57    &lt;uses-permission
58        android:required="true"
59        android:name="android.permission.CHANGE_WIFI_STATE"/&gt;
60    &lt;uses-permission
61        android:required="true"
62        android:name="android.permission.INTERNET"/&gt;
63    ...
64</pre>
65
66<h2 id="register">Add a Local Service</h2>
67<p>If you're providing a local service, you need to register it for
68service discovery.  Once your local service is registered, the framework
69automatically responds to service discovery requests from peers.</p>
70
71<p>To create a local service:</p>
72
73<ol>
74  <li>Create a
75{@link android.net.wifi.p2p.nsd.WifiP2pServiceInfo} object.</li>
76  <li>Populate it with information about your service.</li>
77  <li>Call {@link
78android.net.wifi.p2p.WifiP2pManager#addLocalService(WifiP2pManager.Channel,
79WifiP2pServiceInfo, WifiP2pManager.ActionListener) addLocalService()} to register the local
80service for service discovery.</li>
81</ol>
82
83<pre>
84     private void startRegistration() {
85        //  Create a string map containing information about your service.
86        Map<String,String> record = new HashMap<String,String>();
87        record.put("listenport", String.valueOf(SERVER_PORT));
88        record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
89        record.put("available", "visible");
90
91        // Service information.  Pass it an instance name, service type
92        // _protocol._transportlayer , and the map containing
93        // information other devices will want once they connect to this one.
94        WifiP2pDnsSdServiceInfo serviceInfo =
95                WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence._tcp", record);
96
97        // Add the local service, sending the service info, network channel,
98        // and listener that will be used to indicate success or failure of
99        // the request.
100        mManager.addLocalService(channel, serviceInfo, new ActionListener() {
101            &#64;Override
102            public void onSuccess() {
103                // Command successful! Code isn't necessarily needed here,
104                // Unless you want to update the UI or add logging statements.
105            }
106
107            &#64;Override
108            public void onFailure(int arg0) {
109                // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
110            }
111        });
112    }
113</pre>
114
115<h2 id="discover">Discover Nearby Services</h2>
116<p>Android uses callback methods to notify your application of available services, so
117the first thing to do is set those up.  Create a {@link
118android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener} to listen for
119incoming records.  This record can optionally be broadcast by other
120devices.  When one comes in, copy the device address and any other
121relevant information you want into a data structure external to the current
122method, so you can access it later.  The following example assumes that the
123record contains a "buddyname" field, populated with the user's identity.</p>
124
125<pre>
126final HashMap&lt;String, String&gt; buddies = new HashMap&lt;String, String&gt;();
127...
128private void discoverService() {
129    DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
130        &#64;Override
131        /* Callback includes:
132         * fullDomain: full domain name: e.g "printer._ipp._tcp.local."
133         * record: TXT record dta as a map of key/value pairs.
134         * device: The device running the advertised service.
135         */
136
137        public void onDnsSdTxtRecordAvailable(
138                String fullDomain, Map<String,String> record, WifiP2pDevice device) {
139                Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
140                buddies.put(device.deviceAddress, record.get("buddyname"));
141            }
142        };
143    ...
144}
145</pre>
146
147<p>To get the service information, create a {@link
148android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener}.  This
149receives the actual description and connection information.  The previous code
150snippet implemented a {@link java.util.Map} object to pair a device address with the buddy
151name.  The service response listener uses this to link the DNS record with the
152corresponding service information.  Once both
153listeners are implemented, add them to the {@link
154android.net.wifi.p2p.WifiP2pManager} using the {@link
155android.net.wifi.p2p.WifiP2pManager#setDnsSdResponseListeners(WifiP2pManager.Channel,
156WifiP2pManager.DnsSdServiceResponseListener,
157WifiP2pManager.DnsSdTxtRecordListener) setDnsSdResponseListeners()} method.</p>
158
159<pre>
160private void discoverService() {
161...
162
163    DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
164        &#64;Override
165        public void onDnsSdServiceAvailable(String instanceName, String registrationType,
166                WifiP2pDevice resourceType) {
167
168                // Update the device name with the human-friendly version from
169                // the DnsTxtRecord, assuming one arrived.
170                resourceType.deviceName = buddies
171                        .containsKey(resourceType.deviceAddress) ? buddies
172                        .get(resourceType.deviceAddress) : resourceType.deviceName;
173
174                // Add to the custom adapter defined specifically for showing
175                // wifi devices.
176                WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
177                        .findFragmentById(R.id.frag_peerlist);
178                WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
179                        .getListAdapter());
180
181                adapter.add(resourceType);
182                adapter.notifyDataSetChanged();
183                Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
184        }
185    };
186
187    mManager.setDnsSdResponseListeners(channel, servListener, txtListener);
188    ...
189}
190</pre>
191
192<p>Now create a service request and call {@link
193android.net.wifi.p2p.WifiP2pManager#addServiceRequest(WifiP2pManager.Channel,
194WifiP2pServiceRequest, WifiP2pManager.ActionListener) addServiceRequest()}.
195This method also takes a listener to report success or failure.</p>
196
197<pre>
198        serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
199        mManager.addServiceRequest(channel,
200                serviceRequest,
201                new ActionListener() {
202                    &#64;Override
203                    public void onSuccess() {
204                        // Success!
205                    }
206
207                    &#64;Override
208                    public void onFailure(int code) {
209                        // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
210                    }
211                });
212</pre>
213
214<p>Finally, make the call to {@link
215android.net.wifi.p2p.WifiP2pManager#discoverServices(WifiP2pManager.Channel,
216WifiP2pManager.ActionListener) discoverServices()}.</p>
217
218<pre>
219        mManager.discoverServices(channel, new ActionListener() {
220
221            &#64;Override
222            public void onSuccess() {
223                // Success!
224            }
225
226            &#64;Override
227            public void onFailure(int code) {
228                // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
229                if (code == WifiP2pManager.P2P_UNSUPPORTED) {
230                    Log.d(TAG, "P2P isn't supported on this device.");
231                else if(...)
232                    ...
233            }
234        });
235</pre>
236
237<p>If all goes well, hooray, you're done!  If you encounter problems, remember
238that the asynchronous calls you've made take an
239{@link android.net.wifi.p2p.WifiP2pManager.ActionListener} as an argument, and
240this provides you with callbacks indicating success or failure.  To diagnose
241problems, put debugging code in {@link
242android.net.wifi.p2p.WifiP2pManager.ActionListener#onFailure(int) onFailure()}.  The error code
243provided by the method hints at the problem.  Here are the possible error values
244and what they mean</p>
245<dl>
246  <dt> {@link android.net.wifi.p2p.WifiP2pManager#P2P_UNSUPPORTED}</dt>
247  <dd> Wi-Fi Direct isn't supported on the device running the app.</dd>
248  <dt> {@link android.net.wifi.p2p.WifiP2pManager#BUSY}</dt>
249  <dd> The system is to busy to process the request.</dd>
250  <dt> {@link android.net.wifi.p2p.WifiP2pManager#ERROR}</dt>
251  <dd> The operation failed due to an internal error.</dd>
252</dl>
253