am 320b3ec2: Merge "Initial commit of wireless connectivity/discovery class." into jb-dev
* commit '320b3ec21eff971827a9032f1fb1ee7c866e4303': Initial commit of wireless connectivity/discovery class.
This commit is contained in:
BIN
docs/html/shareables/training/nsdchat.zip
Normal file
BIN
docs/html/shareables/training/nsdchat.zip
Normal file
Binary file not shown.
62
docs/html/training/connect-devices-wirelessly/index.jd
Normal file
62
docs/html/training/connect-devices-wirelessly/index.jd
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
page.title=Connecting Devices Wirelessly
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
startpage=true
|
||||||
|
next.title=Using Network Service Discovery
|
||||||
|
next.link=nsd.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>Dependencies and prerequisites</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Android 4.1 or higher</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi Direct</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Besides enabling communication with the cloud, Android's wireless APIs also
|
||||||
|
enable communication with other devices on the same local network, and even
|
||||||
|
devices which are not on a network, but are physically nearby. The addition of
|
||||||
|
Network Service Discovery (NSD) takes this further by allowing an application to
|
||||||
|
seek out a nearby device running services with which it can communicate.
|
||||||
|
Integrating this functionality into your application helps you provide a wide range
|
||||||
|
of features, such as playing games with users in the same room, pulling
|
||||||
|
images from a networked NSD-enabled webcam, or remotely logging into
|
||||||
|
other machines on the same network.</p>
|
||||||
|
<p>This class describes the key APIs for finding and
|
||||||
|
connecting to other devices from your application. Specifically, it
|
||||||
|
describes the NSD API for discovering available services and the Wi-Fi
|
||||||
|
Direct™ API for doing peer-to-peer wireless connections. This class also
|
||||||
|
shows you how to use NSD and Wi-Fi Direct in
|
||||||
|
combination to detect the services offered by a device and connect to the
|
||||||
|
device when neither device is connected to a network.
|
||||||
|
</p>
|
||||||
|
<h2>Lessons</h2>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><strong><a href="nsd.html">Using Network Service Discovery</a></strong></dt>
|
||||||
|
<dd>Learn how to broadcast services offered by your own application, discover
|
||||||
|
services offered on the local network, and use NSD to determine the connection
|
||||||
|
details for the service you wish to connect to.</dd>
|
||||||
|
<dt><strong><a href="wifi-direct.html">Connecting with Wi-Fi Direct</a></strong></dt>
|
||||||
|
<dd>Learn how to fetch a list of nearby peer devices, create an access point
|
||||||
|
for legacy devices, and connect to other devices capable of Wi-Fi Direct
|
||||||
|
connections.</dd>
|
||||||
|
<dt><strong><a href="nsd-wifi-direct.html">Using Wi-Fi Direct for Service
|
||||||
|
Discovery</a></strong></dt>
|
||||||
|
<dd>Learn how to discover services published by nearby devices without being
|
||||||
|
on the same network, using Wi-Fi Direct.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
252
docs/html/training/connect-devices-wirelessly/nsd-wifi-direct.jd
Normal file
252
docs/html/training/connect-devices-wirelessly/nsd-wifi-direct.jd
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
page.title=Using Wi-Fi Direct for Service Discovery
|
||||||
|
parent.title=Connecting Devices Wirelessly
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#manifest">Set Up the Manifest</a></li>
|
||||||
|
<li><a href="#register">Add a Local Service</a></li>
|
||||||
|
<li><a href="#discover">Discover Nearby Services</a></li>
|
||||||
|
</ol>
|
||||||
|
<!--
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#"></a></li>
|
||||||
|
</ul>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>The first lesson in this class, <a href="nsd.html">Using Network Service
|
||||||
|
Discovery</a>, showed you
|
||||||
|
how to discover services that are connected to a local network. However, using
|
||||||
|
Wi-Fi Direct&trad; Service Discovery allows you to discover the services of nearby devices directly,
|
||||||
|
without being connected to a network. You can also advertise the services
|
||||||
|
running on your device. These capabilities help you communicate between apps,
|
||||||
|
even when no local network or hotspot is available.</p>
|
||||||
|
<p>While this set of APIs is similar in purpose to the Network Service Discovery
|
||||||
|
APIs outlined in a previous lesson, implementing them in code is very different.
|
||||||
|
This lesson shows you how to discover services available from other devices,
|
||||||
|
using Wi-Fi Direct™. The lesson assumes that you're already familiar with the
|
||||||
|
<a href="{@docRoot}guide/topics/connectivity/wifip2p.html">Wi-Fi Direct</a> API.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="manifest">Set Up the Manifest</h2>
|
||||||
|
<p>In order to use Wi-Fi Direct, add the {@link
|
||||||
|
android.Manifest.permission#CHANGE_WIFI_STATE}, {@link
|
||||||
|
android.Manifest.permission#ACCESS_WIFI_STATE},
|
||||||
|
and {@link android.Manifest.permission#INTERNET}
|
||||||
|
permissions to your manifest. Even though Wi-Fi Direct doesn't require an
|
||||||
|
Internet connection, it uses standard Java sockets, and using these in Android
|
||||||
|
requires the requested permissions.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.android.nsdchat"
|
||||||
|
...
|
||||||
|
|
||||||
|
<uses-permission
|
||||||
|
android:required="true"
|
||||||
|
android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||||
|
<uses-permission
|
||||||
|
android:required="true"
|
||||||
|
android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||||
|
<uses-permission
|
||||||
|
android:required="true"
|
||||||
|
android:name="android.permission.INTERNET"/>
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="register">Add a Local Service</h2>
|
||||||
|
<p>If you're providing a local service, you need to register it for
|
||||||
|
service discovery. Once your local service is registered, the framework
|
||||||
|
automatically responds to service discovery requests from peers.</p>
|
||||||
|
|
||||||
|
<p>To create a local service:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Create a
|
||||||
|
{@link android.net.wifi.p2p.nsd.WifiP2pServiceInfo} object.</li>
|
||||||
|
<li>Populate it with information about your service.</li>
|
||||||
|
<li>Call {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#addLocalService(WifiP2pManager.Channel,
|
||||||
|
WifiP2pServiceInfo, WifiP2pManager.ActionListener) addLocalService()} to register the local
|
||||||
|
service for service discovery.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void startRegistration() {
|
||||||
|
// Create a string map containing information about your service.
|
||||||
|
Map<String,String> record = new HashMap<String,String>();
|
||||||
|
record.put("listenport", String.valueOf(SERVER_PORT));
|
||||||
|
record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
|
||||||
|
record.put("available", "visible");
|
||||||
|
|
||||||
|
// Service information. Pass it an instance name, service type
|
||||||
|
// _protocol._transportlayer , and the map containing
|
||||||
|
// information other devices will want once they connect to this one.
|
||||||
|
WifiP2pDnsSdServiceInfo serviceInfo =
|
||||||
|
WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence._tcp", record);
|
||||||
|
|
||||||
|
// Add the local service, sending the service info, network channel,
|
||||||
|
// and listener that will be used to indicate success or failure of
|
||||||
|
// the request.
|
||||||
|
mManager.addLocalService(channel, serviceInfo, new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
// Command successful! Code isn't necessarily needed here,
|
||||||
|
// Unless you want to update the UI or add logging statements.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(int arg0) {
|
||||||
|
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="discover">Discover Nearby Services</h2>
|
||||||
|
<p>Android uses callback methods to notify your application of available services, so
|
||||||
|
the first thing to do is set those up. Create a {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener} to listen for
|
||||||
|
incoming records. This record can optionally be broadcast by other
|
||||||
|
devices. When one comes in, copy the device address and any other
|
||||||
|
relevant information you want into a data structure external to the current
|
||||||
|
method, so you can access it later. The following example assumes that the
|
||||||
|
record contains a "buddyname" field, populated with the user's identity.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
final HashMap<String, String> buddies = new HashMap<String, String>();
|
||||||
|
...
|
||||||
|
private void discoverService() {
|
||||||
|
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
|
||||||
|
@Override
|
||||||
|
/* Callback includes:
|
||||||
|
* fullDomain: full domain name: e.g "printer._ipp._tcp.local."
|
||||||
|
* record: TXT record dta as a map of key/value pairs.
|
||||||
|
* device: The device running the advertised service.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void onDnsSdTxtRecordAvailable(
|
||||||
|
String fullDomain, Map<String,String> record, WifiP2pDevice device) {
|
||||||
|
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
|
||||||
|
buddies.put(device.deviceAddress, record.get("buddyname"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>To get the service information, create a {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener}. This
|
||||||
|
receives the actual description and connection information. The previous code
|
||||||
|
snippet implemented a {@link java.util.Map} object to pair a device address with the buddy
|
||||||
|
name. The service response listener uses this to link the DNS record with the
|
||||||
|
corresponding service information. Once both
|
||||||
|
listeners are implemented, add them to the {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager} using the {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#setDnsSdResponseListeners(WifiP2pManager.Channel,
|
||||||
|
WifiP2pManager.DnsSdServiceResponseListener,
|
||||||
|
WifiP2pManager.DnsSdTxtRecordListener) setDnsSdResponseListeners()} method.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private void discoverService() {
|
||||||
|
...
|
||||||
|
|
||||||
|
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
|
||||||
|
@Override
|
||||||
|
public void onDnsSdServiceAvailable(String instanceName, String registrationType,
|
||||||
|
WifiP2pDevice resourceType) {
|
||||||
|
|
||||||
|
// Update the device name with the human-friendly version from
|
||||||
|
// the DnsTxtRecord, assuming one arrived.
|
||||||
|
resourceType.deviceName = buddies
|
||||||
|
.containsKey(resourceType.deviceAddress) ? buddies
|
||||||
|
.get(resourceType.deviceAddress) : resourceType.deviceName;
|
||||||
|
|
||||||
|
// Add to the custom adapter defined specifically for showing
|
||||||
|
// wifi devices.
|
||||||
|
WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
|
||||||
|
.findFragmentById(R.id.frag_peerlist);
|
||||||
|
WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
|
||||||
|
.getListAdapter());
|
||||||
|
|
||||||
|
adapter.add(resourceType);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mManager.setDnsSdResponseListeners(channel, servListener, txtListener);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now create a service request and call {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#addServiceRequest(WifiP2pManager.Channel,
|
||||||
|
WifiP2pServiceRequest, WifiP2pManager.ActionListener) addServiceRequest()}.
|
||||||
|
This method also takes a listener to report success or failure.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
|
||||||
|
mManager.addServiceRequest(channel,
|
||||||
|
serviceRequest,
|
||||||
|
new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
// Success!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(int code) {
|
||||||
|
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Finally, make the call to {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#discoverServices(WifiP2pManager.Channel,
|
||||||
|
WifiP2pManager.ActionListener) discoverServices()}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
mManager.discoverServices(channel, new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
// Success!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(int code) {
|
||||||
|
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
|
||||||
|
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
|
||||||
|
Log.d(TAG, "P2P isn't supported on this device.");
|
||||||
|
else if(...)
|
||||||
|
...
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If all goes well, hooray, you're done! If you encounter problems, remember
|
||||||
|
that the asynchronous calls you've made take an
|
||||||
|
{@link android.net.wifi.p2p.WifiP2pManager.ActionListener} as an argument, and
|
||||||
|
this provides you with callbacks indicating success or failure. To diagnose
|
||||||
|
problems, put debugging code in {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager.ActionListener#onFailure(int) onFailure()}. The error code
|
||||||
|
provided by the method hints at the problem. Here are the possible error values
|
||||||
|
and what they mean</p>
|
||||||
|
<dl>
|
||||||
|
<dt> {@link android.net.wifi.p2p.WifiP2pManager#P2P_UNSUPPORTED}</dt>
|
||||||
|
<dd> Wi-Fi Direct isn't supported on the device running the app.</dd>
|
||||||
|
<dt> {@link android.net.wifi.p2p.WifiP2pManager#BUSY}</dt>
|
||||||
|
<dd> The system is to busy to process the request.</dd>
|
||||||
|
<dt> {@link android.net.wifi.p2p.WifiP2pManager#ERROR}</dt>
|
||||||
|
<dd> The operation failed due to an internal error.</dd>
|
||||||
|
</dl>
|
||||||
373
docs/html/training/connect-devices-wirelessly/nsd.jd
Normal file
373
docs/html/training/connect-devices-wirelessly/nsd.jd
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
page.title=Using Network Service Discovery
|
||||||
|
parent.title=Connecting Devices Wirelessly
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
next.title=Connecting with Wi-Fi Direct
|
||||||
|
next.link=wifi-direct.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<!-- table of contents -->
|
||||||
|
<h2>This lesson teaches you how to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#register">Register Your Service on the Network</a></li>
|
||||||
|
<li><a href="#discover">Discover Services on the Network</a></li>
|
||||||
|
<li><a href="#connect">Connect to Services on the Network</a></li>
|
||||||
|
<li><a href="#teardown">Unregister Your Service on Application Close</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
</ul>
|
||||||
|
-->
|
||||||
|
<h2>Try it out</h2>
|
||||||
|
|
||||||
|
<div class="download-box">
|
||||||
|
<a href="{@docRoot}shareables/training/nsdchat.zip" class="button">Download
|
||||||
|
the sample app</a>
|
||||||
|
<p class="filename">nsdchat.zip</p>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Adding Network Service Discovery (NSD) to your app allows your users to
|
||||||
|
identify other devices on the local network that support the services your app
|
||||||
|
requests. This is useful for a variety of peer-to-peer applications such as file
|
||||||
|
sharing or multi-player gaming. Android's NSD APIs simplify the effort required
|
||||||
|
for you to implement such features.</p>
|
||||||
|
|
||||||
|
<p>This lesson shows you how to build an application that can broadcast its
|
||||||
|
name and connection information to the local network and scan for information
|
||||||
|
from other applications doing the same. Finally, this lesson shows you how
|
||||||
|
to connect to the same application running on another device.</p>
|
||||||
|
|
||||||
|
<h2 id="register">Register Your Service on the Network</h2>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note: </strong>This step is optional. If
|
||||||
|
you don't care about broadcasting your app's services over the local network,
|
||||||
|
you can skip forward to the
|
||||||
|
next section, <a href="#discover">Discover Services on the Network</a>.</p>
|
||||||
|
|
||||||
|
<p>To register your service on the local network, first create a {@link
|
||||||
|
android.net.nsd.NsdServiceInfo} object. This object provides the information
|
||||||
|
that other devices on the network use when they're deciding whether to connect to your
|
||||||
|
service. </p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public void registerService(int port) {
|
||||||
|
// Create the NsdServiceInfo object, and populate it.
|
||||||
|
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
||||||
|
|
||||||
|
// The name is subject to change based on conflicts
|
||||||
|
// with other services advertised on the same network.
|
||||||
|
serviceInfo.setServiceName("NsdChat");
|
||||||
|
serviceInfo.setServiceType("_http._tcp.");
|
||||||
|
serviceInfo.setPort(port);
|
||||||
|
....
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>This code snippet sets the service name to "NsdChat".
|
||||||
|
The name is visible to any device on the network that is using NSD to look for
|
||||||
|
local services. Keep in mind that the name must be unique for any service on the
|
||||||
|
network, and Android automatically handles conflict resolution. If
|
||||||
|
two devices on the network both have the NsdChat application installed, one of
|
||||||
|
them changes the service name automatically, to something like "NsdChat
|
||||||
|
(1)".</p>
|
||||||
|
|
||||||
|
<p>The second parameter sets the service type, specifies which protocol and transport
|
||||||
|
layer the application uses. The syntax is
|
||||||
|
"_<protocol>._<transportlayer>". In the
|
||||||
|
code snippet, the service uses HTTP protocol running over TCP. An application
|
||||||
|
offering a printer service (for instance, a network printer) would set the
|
||||||
|
service type to "_ipp._tcp".</p>
|
||||||
|
|
||||||
|
<p class="note"><strong>Note: </strong> The International Assigned Numbers
|
||||||
|
Authority (IANA) manages a centralized,
|
||||||
|
authoritative list of service types used by service discovery protocols such as NSD and Bonjour.
|
||||||
|
You can download the list from <a
|
||||||
|
href="http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml">the
|
||||||
|
IANA list of service names and port numbers</a>.
|
||||||
|
If you intend to use a new service type, you should reserve it by filling out
|
||||||
|
the <a
|
||||||
|
href="http://www.iana.org/form/ports-services">IANA Ports and Service
|
||||||
|
registration form</a>.</p>
|
||||||
|
|
||||||
|
<p>When setting the port for your service, avoid hardcoding it as this
|
||||||
|
conflicts with other applications. For instance, assuming
|
||||||
|
that your application always uses port 1337 puts it in potential conflict with
|
||||||
|
other installed applications that use the same port. Instead, use the device's
|
||||||
|
next available port. Because this information is provided to other apps by a
|
||||||
|
service broadcast, there's no need for the port your application uses to be
|
||||||
|
known by other applications at compile-time. Instead, the applications can get
|
||||||
|
this information from your service broadcast, right before connecting to your
|
||||||
|
service.</p>
|
||||||
|
|
||||||
|
<p>If you're working with sockets, here's how you can initialize a socket to any
|
||||||
|
available port simply by setting it to 0.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public void initializeServerSocket() {
|
||||||
|
// Initialize a server socket on the next available port.
|
||||||
|
mServerSocket = new ServerSocket(0);
|
||||||
|
|
||||||
|
// Store the chosen port.
|
||||||
|
mLocalPort = mServerSocket.getLocalPort();
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now that you've defined the {@link android.net.nsd.NsdServiceInfo
|
||||||
|
NsdServiceInfo} object, you need to implement the {@link
|
||||||
|
android.net.nsd.NsdManager.RegistrationListener RegistrationListener} interface. This
|
||||||
|
interface contains callbacks used by Android to alert your application of the
|
||||||
|
success or failure of service registration and unregistration.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
public void initializeRegistrationListener() {
|
||||||
|
mRegistrationListener = new NsdManager.RegistrationListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
|
||||||
|
// Save the service name. Android may have changed it in order to
|
||||||
|
// resolve a conflict, so update the name you initially requested
|
||||||
|
// with the name Android actually used.
|
||||||
|
mServiceName = NsdServiceInfo.getServiceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
// Registration failed! Put debugging code here to determine why.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceUnregistered(NsdServiceInfo arg0) {
|
||||||
|
// Service has been unregistered. This only happens when you call
|
||||||
|
// NsdManager.unregisterService() and pass in this listener.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
// Unregistration failed. Put debugging code here to determine why.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now you have all the pieces to register your service. Call the method
|
||||||
|
{@link android.net.nsd.NsdManager#registerService registerService()}.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Note that this method is asynchronous, so any code that needs to run
|
||||||
|
after the service has been registered must go in the {@link
|
||||||
|
android.net.nsd.NsdManager.RegistrationListener#onServiceRegistered(NsdServiceInfo)
|
||||||
|
onServiceRegistered()} method.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public void registerService(int port) {
|
||||||
|
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
||||||
|
serviceInfo.setServiceName("NsdChat");
|
||||||
|
serviceInfo.setServiceType("_http._tcp.");
|
||||||
|
serviceInfo.setPort(port);
|
||||||
|
|
||||||
|
mNsdManager = Context.getSystemService(Context.NSD_SERVICE);
|
||||||
|
|
||||||
|
mNsdManager.registerService(
|
||||||
|
serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="discover">Discover Services on the Network</h2>
|
||||||
|
<p>The network is teeming with life, from the beastly network printers to the
|
||||||
|
docile network webcams, to the brutal, fiery battles of nearby tic-tac-toe
|
||||||
|
players. The key to letting your application see this vibrant ecosystem of
|
||||||
|
functionality is service discovery. Your application needs to listen to service
|
||||||
|
broadcasts on the network to see what services are available, and filter out
|
||||||
|
anything the application can't work with.</p>
|
||||||
|
|
||||||
|
<p>Service discovery, like service registration, has two steps:
|
||||||
|
setting up a discovery listener with the relevant callbacks, and making a single asynchronous
|
||||||
|
API call to {@link android.net.nsd.NsdManager#discoverServices(String
|
||||||
|
, int , NsdManager.DiscoveryListener) discoverServices()}.</p>
|
||||||
|
|
||||||
|
<p>First, instantiate an anonymous class that implements {@link
|
||||||
|
android.net.nsd.NsdManager.DiscoveryListener}. The following snippet shows a
|
||||||
|
simple example:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public void initializeDiscoveryListener() {
|
||||||
|
|
||||||
|
// Instantiate a new DiscoveryListener
|
||||||
|
mDiscoveryListener = new NsdManager.DiscoveryListener() {
|
||||||
|
|
||||||
|
// Called as soon as service discovery begins.
|
||||||
|
@Override
|
||||||
|
public void onDiscoveryStarted(String regType) {
|
||||||
|
Log.d(TAG, "Service discovery started");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceFound(NsdServiceInfo service) {
|
||||||
|
// A service was found! Do something with it.
|
||||||
|
Log.d(TAG, "Service discovery success" + service);
|
||||||
|
if (!service.getServiceType().equals(SERVICE_TYPE)) {
|
||||||
|
// Service type is the string containing the protocol and
|
||||||
|
// transport layer for this service.
|
||||||
|
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
|
||||||
|
} else if (service.getServiceName().equals(mServiceName)) {
|
||||||
|
// The name of the service tells the user what they'd be
|
||||||
|
// connecting to. It could be "Bob's Chat App".
|
||||||
|
Log.d(TAG, "Same machine: " + mServiceName);
|
||||||
|
} else if (service.getServiceName().contains("NsdChat")){
|
||||||
|
mNsdManager.resolveService(service, mResolveListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceLost(NsdServiceInfo service) {
|
||||||
|
// When the network service is no longer available.
|
||||||
|
// Internal bookkeeping code goes here.
|
||||||
|
Log.e(TAG, "service lost" + service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDiscoveryStopped(String serviceType) {
|
||||||
|
Log.i(TAG, "Discovery stopped: " + serviceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
|
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
|
||||||
|
mNsdManager.stopServiceDiscovery(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
|
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
|
||||||
|
mNsdManager.stopServiceDiscovery(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>The NSD API uses the methods in this interface to inform your application when discovery
|
||||||
|
is started, when it fails, and when services are found and lost (lost means "is
|
||||||
|
no longer available"). Notice that this snippet does several checks
|
||||||
|
when a service is found.</p>
|
||||||
|
<ol>
|
||||||
|
<li>The service name of the found service is compared to the service
|
||||||
|
name of the local service to determine if the device just picked up its own
|
||||||
|
broadcast (which is valid).</li>
|
||||||
|
<li>The service type is checked, to verify it's a type of service your
|
||||||
|
application can connect to.</li>
|
||||||
|
<li>The service name is checked to verify connection to the correct
|
||||||
|
application.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Checking the service name isn't always necessary, and is only relevant if you
|
||||||
|
want to connect to a specific application. For instance, the application might
|
||||||
|
only want to connect to instances of itself running on other devices. However, if the
|
||||||
|
application wants to connect to a network printer, it's enough to see that the service type
|
||||||
|
is "_ipp._tcp".</p>
|
||||||
|
|
||||||
|
<p>After setting up the listener, call {@link android.net.nsd.NsdManager#discoverServices(String, int,
|
||||||
|
NsdManager.DiscoveryListener) discoverServices()}, passing in the service type
|
||||||
|
your application should look for, the discovery protocol to use, and the
|
||||||
|
listener you just created.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
mNsdManager.discoverServices(
|
||||||
|
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="connect">Connect to Services on the Network</h2>
|
||||||
|
<p>When your application finds a service on the network to connect to, it
|
||||||
|
must first determine the connection information for that service, using the
|
||||||
|
{@link android.net.nsd.NsdManager#resolveService resolveService()} method.
|
||||||
|
Implement a {@link android.net.nsd.NsdManager.ResolveListener} to pass into this
|
||||||
|
method, and use it to get a {@link android.net.nsd.NsdServiceInfo} containing
|
||||||
|
the connection information.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public void initializeResolveListener() {
|
||||||
|
mResolveListener = new NsdManager.ResolveListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
// Called when the resolve fails. Use the error code to debug.
|
||||||
|
Log.e(TAG, "Resolve failed" + errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceResolved(NsdServiceInfo serviceInfo) {
|
||||||
|
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
|
||||||
|
|
||||||
|
if (serviceInfo.getServiceName().equals(mServiceName)) {
|
||||||
|
Log.d(TAG, "Same IP.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mService = serviceInfo;
|
||||||
|
int port = mService.getPort();
|
||||||
|
InetAddress host = mService.getHost();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Once the service is resolved, your application receives detailed
|
||||||
|
service information including an IP address and port number. This is everything
|
||||||
|
you need to create your own network connection to the service.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="teardown">Unregister Your Service on Application Close</h2>
|
||||||
|
<p>It's important to enable and disable NSD
|
||||||
|
functionality as appropriate during the application's
|
||||||
|
lifecycle. Unregistering your application when it closes down helps prevent
|
||||||
|
other applications from thinking it's still active and attempting to connect to
|
||||||
|
it. Also, service discovery is an expensive operation, and should be stopped
|
||||||
|
when the parent Activity is paused, and re-enabled when the Activity is
|
||||||
|
resumed. Override the lifecycle methods of your main Activity and insert code
|
||||||
|
to start and stop service broadcast and discovery as appropriate.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
//In your application's Activity
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
if (mNsdHelper != null) {
|
||||||
|
mNsdHelper.tearDown();
|
||||||
|
}
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (mNsdHelper != null) {
|
||||||
|
mNsdHelper.registerService(mConnection.getLocalPort());
|
||||||
|
mNsdHelper.discoverServices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
mNsdHelper.tearDown();
|
||||||
|
mConnection.tearDown();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NsdHelper's tearDown method
|
||||||
|
public void tearDown() {
|
||||||
|
mNsdManager.unregisterService(mRegistrationListener);
|
||||||
|
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
372
docs/html/training/connect-devices-wirelessly/wifi-direct.jd
Normal file
372
docs/html/training/connect-devices-wirelessly/wifi-direct.jd
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
page.title=Connecting with Wi-Fi Direct
|
||||||
|
parent.title=Connecting Devices Wirelessly
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
previous.title=Using Network Service Discovery
|
||||||
|
previous.link=nsd.html
|
||||||
|
next.title=Service Discovery with Wi-Fi Direct
|
||||||
|
next.link=nsd-wifi-direct.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
<h2>This lesson teaches you how to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#permissions">Set Up Application Permissions</a></li>
|
||||||
|
<li><a href="#receiver">Set Up the Broadcast Receiver and Peer-to-Peer
|
||||||
|
Manager</a></li>
|
||||||
|
<li><a href="#discover">Initiate Peer Discovery</a></li>
|
||||||
|
<li><a href="#fetch">Fetch the List of Peers</a></li>
|
||||||
|
<li><a href="#connect">Connect to a Peer</a></li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>The Wi-Fi Direct™ APIs allow applications to connect to nearby devices without
|
||||||
|
needing to connect to a network or hotspot. This allows your application to quickly
|
||||||
|
find and interact with nearby devices, at a range beyond the capabilities of Bluetooth.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This lesson shows you how to find and connect to nearby devices using Wi-Fi Direct.
|
||||||
|
</p>
|
||||||
|
<h2 id="permissions">Set Up Application Permissions</h2>
|
||||||
|
<p>In order to use Wi-Fi Direct, add the {@link
|
||||||
|
android.Manifest.permission#CHANGE_WIFI_STATE}, {@link
|
||||||
|
android.Manifest.permission#ACCESS_WIFI_STATE},
|
||||||
|
and {@link android.Manifest.permission#INTERNET}
|
||||||
|
permissions to your manifest. Wi-Fi Direct doesn't require an internet connection,
|
||||||
|
but it does use standard Java sockets, which require the {@link
|
||||||
|
android.Manifest.permission#INTERNET} permission.
|
||||||
|
So you need the following permissions to use Wi-Fi Direct.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.android.nsdchat"
|
||||||
|
...
|
||||||
|
|
||||||
|
<uses-permission
|
||||||
|
android:required="true"
|
||||||
|
android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||||
|
<uses-permission
|
||||||
|
android:required="true"
|
||||||
|
android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||||
|
<uses-permission
|
||||||
|
android:required="true"
|
||||||
|
android:name="android.permission.INTERNET"/>
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="receiver">Set Up a Broadcast Receiver and Peer-to-Peer Manager</h2>
|
||||||
|
<p>To use Wi-Fi Direct, you need to listen for broadcast intents that tell your
|
||||||
|
application when certain events have occurred. In your application, instantiate
|
||||||
|
an {@link
|
||||||
|
android.content.IntentFilter} and set it to listen for the following:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION}</dt>
|
||||||
|
<dd>Indicates whether Wi-Fi Peer-To-Peer (P2P) is enabled</dd>
|
||||||
|
<dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION}</dt>
|
||||||
|
<dd>Indicates that the available peer list has changed.</dd>
|
||||||
|
<dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION}</dt>
|
||||||
|
<dd>Indicates the state of Wi-Fi P2P connectivity has changed.</dd>
|
||||||
|
<dt>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_THIS_DEVICE_CHANGED_ACTION}</dt>
|
||||||
|
<dd>Indicates this device's configuration details have changed.</dd>
|
||||||
|
<pre>
|
||||||
|
private final IntentFilter intentFilter = new IntentFilter();
|
||||||
|
...
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
|
// Indicates a change in the Wi-Fi Peer-to-Peer status.
|
||||||
|
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
|
||||||
|
|
||||||
|
// Indicates a change in the list of available peers.
|
||||||
|
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
|
||||||
|
|
||||||
|
// Indicates the state of Wi-Fi P2P connectivity has changed.
|
||||||
|
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
|
||||||
|
|
||||||
|
// Indicates this device's details have changed.
|
||||||
|
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>At the end of the {@link android.app.Activity#onCreate onCreate()} method, get an instance of the {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager}, and call its {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#initialize(Context, Looper, WifiP2pManager.ChannelListener) initialize()}
|
||||||
|
method. This method returns a {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager.Channel} object, which you'll use later to
|
||||||
|
connect your app to the Wi-Fi Direct Framework.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@Override
|
||||||
|
|
||||||
|
Channel mChannel;
|
||||||
|
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
....
|
||||||
|
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
|
||||||
|
mChannel = mManager.initialize(this, getMainLooper(), null);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>Now create a new {@link
|
||||||
|
android.content.BroadcastReceiver} class that you'll use to listen for changes
|
||||||
|
to the System's Wi-Fi P2P state. In the {@link
|
||||||
|
android.content.BroadcastReceiver#onReceive(Context, Intent) onReceive()}
|
||||||
|
method, add a condition to handle each P2P state change listed above.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
|
||||||
|
// Determine if Wifi Direct mode is enabled or not, alert
|
||||||
|
// the Activity.
|
||||||
|
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
|
||||||
|
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
|
||||||
|
activity.setIsWifiP2pEnabled(true);
|
||||||
|
} else {
|
||||||
|
activity.setIsWifiP2pEnabled(false);
|
||||||
|
}
|
||||||
|
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
|
||||||
|
|
||||||
|
// The peer list has changed! We should probably do something about
|
||||||
|
// that.
|
||||||
|
|
||||||
|
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
|
||||||
|
|
||||||
|
// Connection state changed! We should probably do something about
|
||||||
|
// that.
|
||||||
|
|
||||||
|
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
|
||||||
|
DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
|
||||||
|
.findFragmentById(R.id.frag_list);
|
||||||
|
fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
|
||||||
|
WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Finally, add code to register the intent filter and broadcast receiver when
|
||||||
|
your main activity is active, and unregister them when the activity is paused.
|
||||||
|
The best place to do this is the {@link android.app.Activity#onResume()} and
|
||||||
|
{@link android.app.Activity#onPause()} methods.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
/** register the BroadcastReceiver with the intent values to be matched */
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
receiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
|
||||||
|
registerReceiver(receiver, intentFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
unregisterReceiver(receiver);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="discover">Initiate Peer Discovery</h2>
|
||||||
|
<p>To start searching for nearby devices with Wi-Fi Direct, call {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#discoverPeers(WifiP2pManager.Channel,
|
||||||
|
WifiP2pManager.ActionListener) discoverPeers()}. This method takes the
|
||||||
|
following arguments:</p>
|
||||||
|
<ul>
|
||||||
|
<li>The {@link android.net.wifi.p2p.WifiP2pManager.Channel} you
|
||||||
|
received back when you initialized the peer-to-peer mManager</li>
|
||||||
|
<li>An implementation of {@link android.net.wifi.p2p.WifiP2pManager.ActionListener} with methods
|
||||||
|
the system invokes for successful and unsuccessful discovery.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
// Code for when the discovery initiation is successful goes here.
|
||||||
|
// No services have actually been discovered yet, so this method
|
||||||
|
// can often be left blank. Code for peer discovery goes in the
|
||||||
|
// onReceive method, detailed below.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(int reasonCode) {
|
||||||
|
// Code for when the discovery initiation fails goes here.
|
||||||
|
// Alert the user that something went wrong.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Keep in mind that this only <em>initiates</em> peer discovery. The
|
||||||
|
{@link android.net.wifi.p2p.WifiP2pManager#discoverPeers(WifiP2pManager.Channel,
|
||||||
|
WifiP2pManager.ActionListener) discoverPeers()} method starts the discovery process and then
|
||||||
|
immediately returns. The system notifies you if the peer discovery process is
|
||||||
|
successfully initiated by calling methods in the provided action listener.
|
||||||
|
Also, discovery will remain active until a connection is initiated or a P2P group is
|
||||||
|
formed.</p>
|
||||||
|
|
||||||
|
<h2 id="fetch">Fetch the List of Peers</h2>
|
||||||
|
<p>Now write the code that fetches and processes the list of peers. First
|
||||||
|
implement the {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener}
|
||||||
|
interface, which provides information about the peers that Wi-Fi Direct has
|
||||||
|
detected. The following code snippet illustrates this.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
|
||||||
|
...
|
||||||
|
|
||||||
|
private PeerListListener peerListListener = new PeerListListener() {
|
||||||
|
@Override
|
||||||
|
public void onPeersAvailable(WifiP2pDeviceList peerList) {
|
||||||
|
|
||||||
|
// Out with the old, in with the new.
|
||||||
|
peers.clear();
|
||||||
|
peers.addAll(peerList.getDeviceList());
|
||||||
|
|
||||||
|
// If an AdapterView is backed by this data, notify it
|
||||||
|
// of the change. For instance, if you have a ListView of available
|
||||||
|
// peers, trigger an update.
|
||||||
|
((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
|
||||||
|
if (peers.size() == 0) {
|
||||||
|
Log.d(WiFiDirectActivity.TAG, "No devices found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now modify your broadcast receiver's {@link
|
||||||
|
android.content.BroadcastReceiver#onReceive(Context, Intent) onReceive()}
|
||||||
|
method to call {@link android.net.wifi.p2p.WifiP2pManager#requestPeers
|
||||||
|
requestPeers()} when an intent with the action {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} is received. You
|
||||||
|
need to pass this listener into the receiver somehow. One way is to send it
|
||||||
|
as an argument to the broadcast receiver's constructor.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
...
|
||||||
|
else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
|
||||||
|
|
||||||
|
// Request available peers from the wifi p2p manager. This is an
|
||||||
|
// asynchronous call and the calling activity is notified with a
|
||||||
|
// callback on PeerListListener.onPeersAvailable()
|
||||||
|
if (mManager != null) {
|
||||||
|
mManager.requestPeers(mChannel, peerListener);
|
||||||
|
}
|
||||||
|
Log.d(WiFiDirectActivity.TAG, "P2P peers changed");
|
||||||
|
}...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now, an intent with the action {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent will
|
||||||
|
trigger a request for an updated peer list. </p>
|
||||||
|
|
||||||
|
<h2 id="connect">Connect to a Peer</h2>
|
||||||
|
<p>In order to connect to a peer, create a new {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pConfig} object, and copy data into it from the
|
||||||
|
{@link android.net.wifi.p2p.WifiP2pDevice} representing the device you want to
|
||||||
|
connect to. Then call the {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#connect(WifiP2pManager.Channel,
|
||||||
|
WifiP2pConfig, WifiP2pManager.ActionListener) connect()}
|
||||||
|
method.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@Override
|
||||||
|
public void connect() {
|
||||||
|
// Picking the first device found on the network.
|
||||||
|
WifiP2pDevice device = peers.get(0);
|
||||||
|
|
||||||
|
WifiP2pConfig config = new WifiP2pConfig();
|
||||||
|
config.deviceAddress = device.deviceAddress;
|
||||||
|
config.wps.setup = WpsInfo.PBC;
|
||||||
|
|
||||||
|
mManager.connect(mChannel, config, new ActionListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess() {
|
||||||
|
// WiFiDirectBroadcastReceiver will notify us. Ignore for now.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(int reason) {
|
||||||
|
Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>The {@link android.net.wifi.p2p.WifiP2pManager.ActionListener} implemented in
|
||||||
|
this snippet only notifies you when the <em>initiation</em> succeeds or fails.
|
||||||
|
To listen for <em>changes</em> in connection state, implement the {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener} interface. Its {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener#onConnectionInfoAvailable(WifiP2pInfo)
|
||||||
|
onConnectionInfoAvailable()}
|
||||||
|
callback will notify you when the state of the connection changes. In cases
|
||||||
|
where multiple devices are going to be connected to a single device (like a game with
|
||||||
|
3 or more players, or a chat app), one device will be designated the "group
|
||||||
|
owner".</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@Override
|
||||||
|
public void onConnectionInfoAvailable(final WifiP2pInfo info) {
|
||||||
|
|
||||||
|
// InetAddress from WifiP2pInfo struct.
|
||||||
|
InetAddress groupOwnerAddress = info.groupOwnerAddress.getHostAddress());
|
||||||
|
|
||||||
|
// After the group negotiation, we can determine the group owner.
|
||||||
|
if (info.groupFormed && info.isGroupOwner) {
|
||||||
|
// Do whatever tasks are specific to the group owner.
|
||||||
|
// One common case is creating a server thread and accepting
|
||||||
|
// incoming connections.
|
||||||
|
} else if (info.groupFormed) {
|
||||||
|
// The other device acts as the client. In this case,
|
||||||
|
// you'll want to create a client thread that connects to the group
|
||||||
|
// owner.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now go back to the {@link
|
||||||
|
android.content.BroadcastReceiver#onReceive(Context, Intent) onReceive()} method of the broadcast receiver, and modify the section
|
||||||
|
that listens for a {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION} intent.
|
||||||
|
When this intent is received, call {@link
|
||||||
|
android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo(WifiP2pManager.Channel,
|
||||||
|
WifiP2pManager.ConnectionInfoListener) requestConnectionInfo()}. This is an
|
||||||
|
asynchronous call, so results will be received by the connection info listener
|
||||||
|
you provide as a parameter.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
|
||||||
|
|
||||||
|
if (mManager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkInfo networkInfo = (NetworkInfo) intent
|
||||||
|
.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
|
||||||
|
|
||||||
|
if (networkInfo.isConnected()) {
|
||||||
|
|
||||||
|
// We are connected with the other device, request connection
|
||||||
|
// info to find group owner IP
|
||||||
|
|
||||||
|
mManager.requestConnectionInfo(mChannel, connectionListener);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
@@ -673,6 +673,27 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="nav-section">
|
||||||
|
<div class="nav-section-header"><a href="<?cs var:toroot ?>training/connect-devices-wirelessly/index.html">
|
||||||
|
<span class="en">Connecting Devices Wirelessly</span>
|
||||||
|
</a></div>
|
||||||
|
<ul>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/connect-devices-wirelessly/nsd.html">
|
||||||
|
<span class="en">Using Network Service Discovery</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/connect-devices-wirelessly/wifi-direct.html">
|
||||||
|
<span class="en">Connecting with Wi-Fi Direct</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/connect-devices-wirelessly/nsd-wifi-direct.html">
|
||||||
|
<span class="en">Using Wi-Fi Direct for Service Discovery</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul><!-- nav -->
|
</ul><!-- nav -->
|
||||||
|
|||||||
Reference in New Issue
Block a user