Merge "WiFi Direct Service Discovery sample" into jb-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
89c08bb50f
16
samples/WiFiDirectServiceDiscovery/Android.mk
Normal file
16
samples/WiFiDirectServiceDiscovery/Android.mk
Normal file
@@ -0,0 +1,16 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := samples
|
||||
|
||||
# Only compile source java files in this apk.
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
|
||||
LOCAL_PACKAGE_NAME := WiFiDirectServiceDiscovery
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
# Use the following include to make our test apk.
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
33
samples/WiFiDirectServiceDiscovery/AndroidManifest.xml
Normal file
33
samples/WiFiDirectServiceDiscovery/AndroidManifest.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.wifidirect.discovery"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="16" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<!-- Google Play filtering -->
|
||||
<uses-feature android:name="android.hardware.wifi.direct" android:required="true"/>
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name" >
|
||||
<activity
|
||||
android:name=".WiFiServiceDiscoveryActivity"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
52
samples/WiFiDirectServiceDiscovery/_index.html
Normal file
52
samples/WiFiDirectServiceDiscovery/_index.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<p>This is a demo application highlighting how to advertise and discover local services that are Wi-Fi peer to peer network capable with
|
||||
the Wi-Fi Direct Service Discovery APIs. Service discovery on Wi-Fi direct allows applications to discover and enagage with peers that support a certain service.
|
||||
As an example, a gaming application can find and associate with devices that support the game. This application allows you to chat with a peer after a succesful connection.</p>
|
||||
|
||||
<p>The source code for this demo app shows how to accomplish three key things
|
||||
with Wi-Fi Direct Service Discovery APIs: Advertise services, discover services and connect to peers advertising such services</p>
|
||||
|
||||
<p>The application includes:<p>
|
||||
<ul> <li><a
|
||||
href="src/com/example/android/wifidirect/discovery/WiFiServiceDiscoveryActivity.html"><code>WiFiServiceDiscoveryActivity</code></a>
|
||||
— the main <code>Activity</code> that contains two fragments to handle app's UI. It advertises and discovers services and also registers a broadcast receiver for Wi-Fi Direct related events.</li> <li><a
|
||||
href="src/com/example/android/wifidirect/discovery/WiFiDirectBroadcastReceiver.html"><code>
|
||||
WiFiDirectBroadcastReceiver</code></a> — a <code>BroadcastReceiver</code>
|
||||
that listens for Wi-Fi Direct related events and passes them to
|
||||
<code>WiFiServiceDiscoveryActivity</code> and it's fragments for neccesary action.</li> <li><a
|
||||
href="src/com/example/android/wifidirect/discovery/WiFiDirectServicesList.html"><code>WiFiDirectServicesList</code></a>
|
||||
— a <code>ListFragment</code> that displays available services, peers and their status. </li>
|
||||
<li><a href="src/com/example/android/wifidirect/discovery/WiFiChatFragment.html"><code>WiFiChatFragment</code></a>
|
||||
— a <code>Fragment</code> that displays handles chat UI </li>
|
||||
<li><a href="src/com/example/android/wifidirect/discovery/ChatManager.html"><code>ChatManager</code></a>
|
||||
— a <code>Runnable</code> that continously performs Socket I/O.</li>
|
||||
<li><a href="src/com/example/android/wifidirect/discovery/GroupOwnerSocketHandler.html"><code>GroupOwnerSocketHandler</code></a>
|
||||
— a <code>Thread</code> that implements a server side Socket handler and spawns a client socket per connection.</li> </ul>
|
||||
<li><a href="src/com/example/android/wifidirect/discovery/ClientSocketHandler.html"><code>GroupOwnerSocketHandler</code></a>
|
||||
— a <code>Thread</code> that implements a client side Socket handler.</li> </ul>
|
||||
<p>If you are developing an application that uses the Wi-Fi Direct Service Discovery APIs, remember that the
|
||||
feature is supported only on Android 4.1 (API level 16) and higher versions of
|
||||
the platform. To ensure that your application can only
|
||||
be installed on devices that are capable of supporting Wi-Fi Direct Service Discovery, remember to add the
|
||||
following to the application's manifest before publishing to Google Play:</p>
|
||||
<ul> <li><code><uses-sdk android:minSdkVersion="16" /></code>, which
|
||||
indicates to Google Play and the platform that your application requires
|
||||
Android 4.1 or higher. For more information, see <a
|
||||
href="../../../guide/appendix/api-levels.html">API Levels</a> and the
|
||||
documentation for the <a
|
||||
href="../../../guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a>
|
||||
element.</li> </ul> <p>To control how Google Play filters your application
|
||||
from devices that do not support Wi-Fi Direct mode, remember to add the following to the
|
||||
application's manifest <ul> <li><code><uses-feature
|
||||
android:name="android.hardware.wifi.direct" /></code>, which tells Google
|
||||
Play that your application uses the Wi-Fi Direct API. The declaration should include
|
||||
an <code>android:required</code> attribute that indicates whether you want
|
||||
Google Play to filter the application from devices that do not offer Wi-Fi Direct support. Other <code><uses-feature></code> declarations may also be
|
||||
needed, depending on your implementation. For more information, see the
|
||||
documentation for the <a
|
||||
href="../../../guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
|
||||
element.</li> </ul>
|
||||
<p>For more information about using the Wi-Fi Direct Service Discovery APIs, see the <a
|
||||
href="../../../reference/android/net/wifi/p2p/package-summary.html"><code>android.net.wifi.p2p </a></code>
|
||||
documentation. </p>
|
||||
|
||||
<img alt="" src="../images/WifiDirect.png" />
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="top"
|
||||
android:gravity="top" >
|
||||
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
</ListView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dip">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:text="@string/finding_service" >
|
||||
</TextView>
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginLeft="20dip"
|
||||
style="@android:style/Widget.ProgressBar.Small" >
|
||||
</ProgressBar>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="50dip"
|
||||
android:transcriptMode="alwaysScroll" >
|
||||
|
||||
<!-- Preview: listitem=@android:layout/simple_list_item_1 -->
|
||||
|
||||
</ListView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dip"
|
||||
android:layout_gravity="bottom" >
|
||||
|
||||
<EditText
|
||||
android:id="@+id/txtChatLine"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_weight="0.90"
|
||||
android:focusableInTouchMode="true"
|
||||
android:hint="@string/txt_hint"
|
||||
android:visibility="visible" >
|
||||
</EditText>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_weight="0.10"
|
||||
android:text="@string/btn_send" />
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
22
samples/WiFiDirectServiceDiscovery/res/layout/main.xml
Normal file
22
samples/WiFiDirectServiceDiscovery/res/layout/main.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container_root"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="top"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" >
|
||||
</TextView>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="finding_service">Finding local services</string>
|
||||
<string name="btn_send">Send</string>
|
||||
<string name="txt_hint">Type Message</string>
|
||||
<string name="app_name">Wi-Fi Discovery</string>
|
||||
|
||||
</resources>
|
||||
14
samples/WiFiDirectServiceDiscovery/res/values/style.xml
Normal file
14
samples/WiFiDirectServiceDiscovery/res/values/style.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="boldText">
|
||||
<item name="android:textStyle">bold|italic</item>
|
||||
<item name="android:textColor">#99CC00</item>
|
||||
</style>
|
||||
|
||||
<style name="normalText">
|
||||
<item name="android:textStyle">normal</item>
|
||||
<item name="android:textColor">#33B5E5</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Handles reading and writing of messages with socket buffers. Uses a Handler
|
||||
* to post messages to UI thread for UI updates.
|
||||
*/
|
||||
public class ChatManager implements Runnable {
|
||||
|
||||
private Socket socket = null;
|
||||
private Handler handler;
|
||||
|
||||
public ChatManager(Socket socket, Handler handler) {
|
||||
this.socket = socket;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
private InputStream iStream;
|
||||
private OutputStream oStream;
|
||||
private static final String TAG = "ChatHandler";
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
iStream = socket.getInputStream();
|
||||
oStream = socket.getOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytes;
|
||||
handler.obtainMessage(WiFiServiceDiscoveryActivity.MY_HANDLE, this)
|
||||
.sendToTarget();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
// Read from the InputStream
|
||||
bytes = iStream.read(buffer);
|
||||
if (bytes == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Send the obtained bytes to the UI Activity
|
||||
Log.d(TAG, "Rec:" + String.valueOf(buffer));
|
||||
handler.obtainMessage(WiFiServiceDiscoveryActivity.MESSAGE_READ,
|
||||
bytes, -1, buffer).sendToTarget();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "disconnected", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(byte[] buffer) {
|
||||
try {
|
||||
oStream.write(buffer);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Exception during write", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
public class ClientSocketHandler extends Thread {
|
||||
|
||||
private static final String TAG = "ClientSocketHandler";
|
||||
private Handler handler;
|
||||
private ChatManager chat;
|
||||
private InetAddress mAddress;
|
||||
|
||||
public ClientSocketHandler(Handler handler, InetAddress groupOwnerAddress) {
|
||||
this.handler = handler;
|
||||
this.mAddress = groupOwnerAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Socket socket = new Socket();
|
||||
try {
|
||||
socket.bind(null);
|
||||
socket.connect(new InetSocketAddress(mAddress.getHostAddress(),
|
||||
WiFiServiceDiscoveryActivity.SERVER_PORT), 5000);
|
||||
Log.d(TAG, "Launching the I/O handler");
|
||||
chat = new ChatManager(socket, handler);
|
||||
new Thread(chat).start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public ChatManager getChat() {
|
||||
return chat;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The implementation of a ServerSocket handler. This is used by the wifi p2p
|
||||
* group owner.
|
||||
*/
|
||||
public class GroupOwnerSocketHandler extends Thread {
|
||||
|
||||
ServerSocket socket = null;
|
||||
private final int THREAD_COUNT = 10;
|
||||
private Handler handler;
|
||||
private static final String TAG = "GroupOwnerSocketHandler";
|
||||
|
||||
public GroupOwnerSocketHandler(Handler handler) throws IOException {
|
||||
try {
|
||||
socket = new ServerSocket(4545);
|
||||
this.handler = handler;
|
||||
Log.d("GroupOwnerSocketHandler", "Socket Started");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
pool.shutdownNow();
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A ThreadPool for client sockets.
|
||||
*/
|
||||
private final ThreadPoolExecutor pool = new ThreadPoolExecutor(
|
||||
THREAD_COUNT, THREAD_COUNT, 10, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
// A blocking operation. Initiate a ChatManager instance when
|
||||
// there is a new connection
|
||||
pool.execute(new ChatManager(socket.accept(), handler));
|
||||
Log.d(TAG, "Launching the I/O handler");
|
||||
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
if (socket != null && !socket.isClosed())
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
|
||||
}
|
||||
e.printStackTrace();
|
||||
pool.shutdownNow();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This fragment handles chat related UI which includes a list view for messages
|
||||
* and a message entry field with send button.
|
||||
*/
|
||||
public class WiFiChatFragment extends Fragment {
|
||||
|
||||
private View view;
|
||||
private ChatManager chatManager;
|
||||
private TextView chatLine;
|
||||
private ListView listView;
|
||||
ChatMessageAdapter adapter = null;
|
||||
private List<String> items = new ArrayList<String>();
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
view = inflater.inflate(R.layout.fragment_chat, container, false);
|
||||
chatLine = (TextView) view.findViewById(R.id.txtChatLine);
|
||||
listView = (ListView) view.findViewById(android.R.id.list);
|
||||
adapter = new ChatMessageAdapter(getActivity(), android.R.id.text1,
|
||||
items);
|
||||
listView.setAdapter(adapter);
|
||||
view.findViewById(R.id.button1).setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
if (chatManager != null) {
|
||||
chatManager.write(chatLine.getText().toString()
|
||||
.getBytes());
|
||||
pushMessage("Me: " + chatLine.getText().toString());
|
||||
chatLine.setText("");
|
||||
chatLine.clearFocus();
|
||||
}
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
|
||||
public interface MessageTarget {
|
||||
public Handler getHandler();
|
||||
}
|
||||
|
||||
public void setChatManager(ChatManager obj) {
|
||||
chatManager = obj;
|
||||
}
|
||||
|
||||
public void pushMessage(String readMessage) {
|
||||
adapter.add(readMessage);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* ArrayAdapter to manage chat messages.
|
||||
*/
|
||||
public class ChatMessageAdapter extends ArrayAdapter<String> {
|
||||
|
||||
List<String> messages = null;
|
||||
|
||||
public ChatMessageAdapter(Context context, int textViewResourceId,
|
||||
List<String> items) {
|
||||
super(context, textViewResourceId, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View v = convertView;
|
||||
if (v == null) {
|
||||
LayoutInflater vi = (LayoutInflater) getActivity()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(android.R.layout.simple_list_item_1, null);
|
||||
}
|
||||
String message = items.get(position);
|
||||
if (message != null && !message.isEmpty()) {
|
||||
TextView nameText = (TextView) v
|
||||
.findViewById(android.R.id.text1);
|
||||
|
||||
if (nameText != null) {
|
||||
nameText.setText(message);
|
||||
if (message.startsWith("Me: ")) {
|
||||
nameText.setTextAppearance(getActivity(),
|
||||
R.style.normalText);
|
||||
} else {
|
||||
nameText.setTextAppearance(getActivity(),
|
||||
R.style.boldText);
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.net.wifi.p2p.WifiP2pManager.Channel;
|
||||
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A BroadcastReceiver that notifies of important wifi p2p events.
|
||||
*/
|
||||
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
private WifiP2pManager manager;
|
||||
private Channel channel;
|
||||
private Activity activity;
|
||||
|
||||
/**
|
||||
* @param manager WifiP2pManager system service
|
||||
* @param channel Wifi p2p channel
|
||||
* @param activity activity associated with the receiver
|
||||
*/
|
||||
public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
|
||||
Activity activity) {
|
||||
super();
|
||||
this.manager = manager;
|
||||
this.channel = channel;
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see android.content.BroadcastReceiver#onReceive(android.content.Context,
|
||||
* android.content.Intent)
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Log.d(WiFiServiceDiscoveryActivity.TAG, action);
|
||||
if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
|
||||
|
||||
if (manager == 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
|
||||
Log.d(WiFiServiceDiscoveryActivity.TAG,
|
||||
"Connected to p2p network. Requesting network details");
|
||||
manager.requestConnectionInfo(channel,
|
||||
(ConnectionInfoListener) activity);
|
||||
} else {
|
||||
// It's a disconnect
|
||||
}
|
||||
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
|
||||
.equals(action)) {
|
||||
|
||||
WifiP2pDevice device = (WifiP2pDevice) intent
|
||||
.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
|
||||
Log.d(WiFiServiceDiscoveryActivity.TAG, "Device status -" + device.status);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.content.Context;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple ListFragment that shows the available services as published by the
|
||||
* peers
|
||||
*/
|
||||
public class WiFiDirectServicesList extends ListFragment {
|
||||
|
||||
WiFiDevicesAdapter listAdapter = null;
|
||||
|
||||
interface DeviceClickListener {
|
||||
public void connectP2p(WiFiP2pService wifiP2pService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.devices_list, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
listAdapter = new WiFiDevicesAdapter(this.getActivity(),
|
||||
android.R.layout.simple_list_item_2, android.R.id.text1,
|
||||
new ArrayList<WiFiP2pService>());
|
||||
setListAdapter(listAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||
// TODO Auto-generated method stub
|
||||
((DeviceClickListener) getActivity()).connectP2p((WiFiP2pService) l
|
||||
.getItemAtPosition(position));
|
||||
((TextView) v.findViewById(android.R.id.text2)).setText("Connecting");
|
||||
|
||||
}
|
||||
|
||||
public class WiFiDevicesAdapter extends ArrayAdapter<WiFiP2pService> {
|
||||
|
||||
private List<WiFiP2pService> items;
|
||||
|
||||
public WiFiDevicesAdapter(Context context, int resource,
|
||||
int textViewResourceId, List<WiFiP2pService> items) {
|
||||
super(context, resource, textViewResourceId, items);
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View v = convertView;
|
||||
if (v == null) {
|
||||
LayoutInflater vi = (LayoutInflater) getActivity()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(android.R.layout.simple_list_item_2, null);
|
||||
}
|
||||
WiFiP2pService service = items.get(position);
|
||||
if (service != null) {
|
||||
TextView nameText = (TextView) v
|
||||
.findViewById(android.R.id.text1);
|
||||
|
||||
if (nameText != null) {
|
||||
nameText.setText(service.device.deviceName + " - " + service.instanceName);
|
||||
}
|
||||
TextView statusText = (TextView) v
|
||||
.findViewById(android.R.id.text2);
|
||||
statusText.setText(getDeviceStatus(service.device.status));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String getDeviceStatus(int statusCode) {
|
||||
switch (statusCode) {
|
||||
case WifiP2pDevice.CONNECTED:
|
||||
return "Connected";
|
||||
case WifiP2pDevice.INVITED:
|
||||
return "Invited";
|
||||
case WifiP2pDevice.FAILED:
|
||||
return "Failed";
|
||||
case WifiP2pDevice.AVAILABLE:
|
||||
return "Available";
|
||||
case WifiP2pDevice.UNAVAILABLE:
|
||||
return "Unavailable";
|
||||
default:
|
||||
return "Unknown";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
|
||||
/**
|
||||
* A structure to hold service information.
|
||||
*/
|
||||
public class WiFiP2pService {
|
||||
WifiP2pDevice device;
|
||||
String instanceName = null;
|
||||
String serviceRegistrationType = null;
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
|
||||
package com.example.android.wifidirect.discovery;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.wifi.WpsInfo;
|
||||
import android.net.wifi.p2p.WifiP2pConfig;
|
||||
import android.net.wifi.p2p.WifiP2pDevice;
|
||||
import android.net.wifi.p2p.WifiP2pInfo;
|
||||
import android.net.wifi.p2p.WifiP2pManager;
|
||||
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
|
||||
import android.net.wifi.p2p.WifiP2pManager.Channel;
|
||||
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
|
||||
import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
|
||||
import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
|
||||
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.example.android.wifidirect.discovery.WiFiChatFragment.MessageTarget;
|
||||
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.DeviceClickListener;
|
||||
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.WiFiDevicesAdapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The main activity for the sample. This activity registers a local service and
|
||||
* perform discovery over Wi-Fi p2p network. It also hosts a couple of fragments
|
||||
* to manage chat operations. When the app is launched, the device publishes a
|
||||
* chat service and also tries to discover services published by other peers. On
|
||||
* selecting a peer published service, the app initiates a Wi-Fi P2P (Direct)
|
||||
* connection with the peer. On successful connection with a peer advertising
|
||||
* the same service, the app opens up sockets to initiate a chat.
|
||||
* {@code WiFiChatFragment} is then added to the the main activity which manages
|
||||
* the interface and messaging needs for a chat session.
|
||||
*/
|
||||
public class WiFiServiceDiscoveryActivity extends Activity implements
|
||||
DeviceClickListener, Handler.Callback, MessageTarget,
|
||||
ConnectionInfoListener {
|
||||
|
||||
public static final String TAG = "wifidirectdemo";
|
||||
|
||||
// TXT RECORD properties
|
||||
public static final String TXTRECORD_PROP_AVAILABLE = "available";
|
||||
public static final String SERVICE_INSTANCE = "_wifidemotest";
|
||||
public static final String SERVICE_REG_TYPE = "_presence._tcp";
|
||||
|
||||
public static final int MESSAGE_READ = 0x400 + 1;
|
||||
public static final int MY_HANDLE = 0x400 + 2;
|
||||
private WifiP2pManager manager;
|
||||
|
||||
static final int SERVER_PORT = 4545;
|
||||
|
||||
private final IntentFilter intentFilter = new IntentFilter();
|
||||
private Channel channel;
|
||||
private BroadcastReceiver receiver = null;
|
||||
private WifiP2pDnsSdServiceRequest serviceRequest;
|
||||
|
||||
private Handler handler = new Handler(this);
|
||||
private WiFiChatFragment chatFragment;
|
||||
private WiFiDirectServicesList servicesList;
|
||||
|
||||
private TextView statusTxtView;
|
||||
|
||||
public Handler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void setHandler(Handler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
statusTxtView = (TextView) findViewById(R.id.status_text);
|
||||
|
||||
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
|
||||
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
|
||||
intentFilter
|
||||
.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
|
||||
intentFilter
|
||||
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
|
||||
|
||||
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
|
||||
channel = manager.initialize(this, getMainLooper(), null);
|
||||
startRegistrationAndDiscovery();
|
||||
|
||||
servicesList = new WiFiDirectServicesList();
|
||||
getFragmentManager().beginTransaction()
|
||||
.add(R.id.container_root, servicesList, "services").commit();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestart() {
|
||||
Fragment frag = getFragmentManager().findFragmentByTag("services");
|
||||
if (frag != null) {
|
||||
getFragmentManager().beginTransaction().remove(frag).commit();
|
||||
}
|
||||
super.onRestart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (manager != null && channel != null) {
|
||||
manager.removeGroup(channel, new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onFailure(int reasonCode) {
|
||||
Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a local service and then initiates a service discovery
|
||||
*/
|
||||
private void startRegistrationAndDiscovery() {
|
||||
Map<String, String> record = new HashMap<String, String>();
|
||||
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
|
||||
|
||||
WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
|
||||
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
|
||||
manager.addLocalService(channel, service, new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
appendStatus("Added Local Service");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int error) {
|
||||
appendStatus("Failed to add a service");
|
||||
}
|
||||
});
|
||||
|
||||
discoverService();
|
||||
|
||||
}
|
||||
|
||||
private void discoverService() {
|
||||
|
||||
/*
|
||||
* Register listeners for DNS-SD services. These are callbacks invoked
|
||||
* by the system when a service is actually discovered.
|
||||
*/
|
||||
|
||||
manager.setDnsSdResponseListeners(channel,
|
||||
new DnsSdServiceResponseListener() {
|
||||
|
||||
@Override
|
||||
public void onDnsSdServiceAvailable(String instanceName,
|
||||
String registrationType, WifiP2pDevice srcDevice) {
|
||||
|
||||
// A service has been discovered. Is this our app?
|
||||
|
||||
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
|
||||
|
||||
// update the UI and add the item the discovered
|
||||
// device.
|
||||
WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
|
||||
.findFragmentByTag("services");
|
||||
if (fragment != null) {
|
||||
WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
|
||||
.getListAdapter());
|
||||
WiFiP2pService service = new WiFiP2pService();
|
||||
service.device = srcDevice;
|
||||
service.instanceName = instanceName;
|
||||
service.serviceRegistrationType = registrationType;
|
||||
adapter.add(service);
|
||||
adapter.notifyDataSetChanged();
|
||||
Log.d(TAG, "onBonjourServiceAvailable "
|
||||
+ instanceName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}, new DnsSdTxtRecordListener() {
|
||||
|
||||
/**
|
||||
* A new TXT record is available. Pick up the advertised
|
||||
* buddy name.
|
||||
*/
|
||||
@Override
|
||||
public void onDnsSdTxtRecordAvailable(
|
||||
String fullDomainName, Map<String, String> record,
|
||||
WifiP2pDevice device) {
|
||||
Log.d(TAG,
|
||||
device.deviceName + " is "
|
||||
+ record.get(TXTRECORD_PROP_AVAILABLE));
|
||||
}
|
||||
});
|
||||
|
||||
// After attaching listeners, create a service request and initiate
|
||||
// discovery.
|
||||
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
|
||||
manager.addServiceRequest(channel, serviceRequest,
|
||||
new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
appendStatus("Added service discovery request");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int arg0) {
|
||||
appendStatus("Failed adding service discovery request");
|
||||
}
|
||||
});
|
||||
manager.discoverServices(channel, new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
appendStatus("Service discovery initiated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int arg0) {
|
||||
appendStatus("Service discovery failed");
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectP2p(WiFiP2pService service) {
|
||||
WifiP2pConfig config = new WifiP2pConfig();
|
||||
config.deviceAddress = service.device.deviceAddress;
|
||||
config.wps.setup = WpsInfo.PBC;
|
||||
if (serviceRequest != null)
|
||||
manager.removeServiceRequest(channel, serviceRequest,
|
||||
new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int arg0) {
|
||||
}
|
||||
});
|
||||
|
||||
manager.connect(channel, config, new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
appendStatus("Connecting to service");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int errorCode) {
|
||||
appendStatus("Failed connecting to service");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MESSAGE_READ:
|
||||
byte[] readBuf = (byte[]) msg.obj;
|
||||
// construct a string from the valid bytes in the buffer
|
||||
String readMessage = new String(readBuf, 0, msg.arg1);
|
||||
Log.d(TAG, readMessage);
|
||||
(chatFragment).pushMessage("Buddy: " + readMessage);
|
||||
break;
|
||||
|
||||
case MY_HANDLE:
|
||||
Object obj = msg.obj;
|
||||
(chatFragment).setChatManager((ChatManager) obj);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
|
||||
registerReceiver(receiver, intentFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo) {
|
||||
Thread handler = null;
|
||||
/*
|
||||
* The group owner accepts connections using a server socket and then spawns a
|
||||
* client socket for every client. This is handled by {@code
|
||||
* GroupOwnerSocketHandler}
|
||||
*/
|
||||
|
||||
if (p2pInfo.isGroupOwner) {
|
||||
Log.d(TAG, "Connected as group owner");
|
||||
try {
|
||||
handler = new GroupOwnerSocketHandler(
|
||||
((MessageTarget) this).getHandler());
|
||||
handler.start();
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG,
|
||||
"Failed to create a server thread - " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Connected as peer");
|
||||
handler = new ClientSocketHandler(
|
||||
((MessageTarget) this).getHandler(),
|
||||
p2pInfo.groupOwnerAddress);
|
||||
handler.start();
|
||||
}
|
||||
chatFragment = new WiFiChatFragment();
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(R.id.container_root, chatFragment).commit();
|
||||
statusTxtView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void appendStatus(String status) {
|
||||
String current = statusTxtView.getText().toString();
|
||||
statusTxtView.setText(current + "\n" + status);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user