橘子味的心
标题:8.14 WIFI Direct开发实例演示

实例 WIFIDirectDemo 改编 Android SDK 提供的实例,演示了通过 WIFI 搜寻连接点,建立连接,并进行数据传输的过程。

该实例包含 5 个类,说明说下:
  • WIFIDirectDemoActivity:用于注册 BroadcastReceiver,处理 UI,并管理连接点的生命周期。
  • WiFiDirectBroadcastReceiver:用于接收与 WIFI Direct 功能相关的 Intent。
  • DeviceListFragment:用于显示可以连接点列表及其状态。
  • FileTransferService:通过 TCP 协议在客户端与服务器之间进行文件传输的 IntentService。
  • IntentService:Sevice 的子类,用于处理异步请求。

该实例的运行效果如图 1 所示。
实例WIFIDirectDemo的运行效果
图 1  实例WIFIDirectDemo的运行效果

WIFIDirectDemo 的 AndroidManifest.xml 文件内容如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="introduction.android.wifidirectdemo">
  4.  
  5. <uses-sdk android:minSdkVersion="14" />
  6.  
  7. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  8. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
  9. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  10. <uses-permission android:name="android.permission.INTERNET" />
  11. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  12. <uses-permission android:name="android.permission.READ_CONTACTS" />
  13. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  14.  
  15. <!--Market filtering -->
  16. <uses-feature
  17. android:name="android.hardware.wifi.direct"
  18. android:required="true" />
  19. <application
  20. android:allowBackup="true"
  21. android:icon="@mipmap/ic_launcher"
  22. android:label="@string/app_name"
  23. android:roundIcon="@mipmap/ic_launcher_round"
  24. android:supportsRtl="true"
  25. android:theme="@style/AppTheme">
  26. <activity android:name=".WIFIDirectDemoActivity">
  27. <intent-filter>
  28. <action android:name="android.intent.action.MAIN" />
  29.  
  30. <category android:name="android.intent.category.LAUNCHER" />
  31. </intent-filter>
  32. </activity>
  33. </application>
  34.  
  35. </manifest>
WIFIDirectDemoActivity.java 的代码如下:
  1. package introduction.android.wifidirectdemo;
  2.  
  3. import android.app.Activity;
  4. import android.content.BroadcastReceiver;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.content.IntentFilter;
  8. import android.net.wifi.p2p.WifiP2pConfig;
  9. import android.net.wifi.p2p.WifiP2pDevice;
  10. import android.net.wifi.p2p.WifiP2pManager;
  11. import android.net.wifi.p2p.WifiP2pManager.ActionListener;
  12. import android.net.wifi.p2p.WifiP2pManager.Channel;
  13. import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
  14. import android.os.Bundle;
  15. import android.provider.Settings;
  16. import android.util.Log;
  17. import android.view.Menu;
  18. import android.view.MenuInflater;
  19. import android.view.MenuItem;
  20. import android.view.View;
  21. import android.widget.Toast;
  22.  
  23.  
  24. public class WIFIDirectDemoActivity extends Activity implements ChannelListener, DeviceListFragment.WiFiPeerListAdapter.DeviceActionListener {
  25.  
  26. public static final String TAG = "wifidirectdemo";
  27. private WifiP2pManager manager;
  28. private boolean isWifiP2pEnabled = false;
  29. private boolean retryChannel = false;
  30. private final IntentFilter intentFilter = new IntentFilter();
  31. private Channel channel;
  32. private BroadcastReceiver receiver = null;
  33.  
  34. public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
  35. this.isWifiP2pEnabled = isWifiP2pEnabled;
  36. }
  37.  
  38. public void onCreate(Bundle savedInstanceState) {
  39. super.onCreate(savedInstanceState);
  40. setContentView(R.layout.main);
  41.  
  42. // add necessary intent values to be matched.
  43. intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTI0N);
  44. intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTI0N);
  45. intentFilter.addAction(WifiP2pManager.WIFI_P2P_C0NNECTI0N_CHANGED_ACTI0N);
  46. intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTI0N);
  47. manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
  48. channel = manager.initialize(this, getMainLooper(), null);
  49. }
  50.  
  51. /**
  52. * register the BroadcastReceiver with the intent values to be matched
  53. */
  54. public void onResume() {
  55. super.onResume();
  56. receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
  57. registerReceiver(receiver, intentFilter);
  58. }
  59.  
  60. public void onPause() {
  61. super.onPause();
  62. unregisterReceiver(receiver);
  63. }
  64. /*
  65. *Remove all peers and clear all fields.This is called on
  66. *BroadcastReceiver receiving a state change event.
  67. */
  68.  
  69. public void resetData() {
  70. DeviceListFragment fragmentList = (DeviceListFragment) getFragmentManager()
  71. .findFragmentById(R.id.frag_list);
  72. DeviceDetailFragment1 fragmentDetails = (DeviceDetailFragment1) getFragmentManager().findFragmentById(R.id.frag_detail);
  73. if (fragmentList != null) {
  74. fragmentList.clearPeers();
  75. }
  76. if (fragmentDetails != null) {
  77. fragmentDetails.resetViews();
  78. }
  79. }
  80.  
  81. public boolean onCreateOptionsMenu(Menu menu) {
  82. MenuInflater inflater = getMenuInflater();
  83. inflater.inflate(R.menu.action_items, menu);
  84. return true;
  85. }
  86.  
  87. public boolean onOptionsItemSelected(MenuItem item) {
  88. switch (item.getItemId()) {
  89. case R.id.atn_direct_enable:
  90. if (manager != null && channel != null) {
  91. startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
  92. } else {
  93. Log.e(TAG, "channel or manager is null");
  94. }
  95. return true;
  96. case R.id.atn_direct_discover:
  97. if (!isWifiP2pEnabled) {
  98. Toast.makeText(WIFIDirectDemoActivity.this, R.string.p2p_off_warning, Toast.LENGTHJSHORT).show();
  99. return true;
  100.  
  101. }
  102. final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager().findFragmentByld(R.id.frag_list);
  103. fragment.onInitiateDiscovery();
  104. manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
  105. public void onSuccess() {
  106. Toast.makeText(WIFIDirectDemoActivity.this, "Discovery Initiated", Toast.LENGTH_SHORT).show();
  107. }
  108.  
  109. public void onFailure(int reasonCode) {
  110. Toast.makeText(WIFIDirectDemoActivity.this, "Discovery Failed " + reasonCode, Toast.LENGTH_SHORT).show();
  111. }
  112. });
  113. return true;
  114. default:
  115. return super.onOptionsItemSelected(item);
  116. }
  117. }
  118.  
  119. public void showDetails(WifiP2pDevice device) {
  120. DeviceDetailFragmentl fragment = (DeviceDetailFragmentl) getFragmentManager().findFragmentById(R.id.frag_detail);
  121. fragment.showDetails(device);
  122. }
  123.  
  124. public void connect(WifiP2pConfig config) {
  125. manager.connect(channel, config, new ActionListener() {
  126. public void onSuccess() {
  127. // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
  128. }
  129.  
  130. public void onFailure(int reason) {
  131. Toast.makeText(WIFIDirectDemoActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show();
  132. }
  133. });
  134. }
  135.  
  136. public void disconnect() {
  137. final DeviceDetailFragmentl fragment = (DeviceDetailFragmentl) getFragmentManager().findFragmentById(R.id.frag_detail);
  138. fragment.resetViews();
  139. manager.removeGroup(channel, new ActionListener() {
  140. public void onFailure(int reasonCode) {
  141. Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
  142. }
  143.  
  144. public void onSuccess() {
  145. fragment.getView().setVisibility(View.GONE);
  146. }
  147. });
  148. }
  149.  
  150. public void onChannelDisconnected() {
  151. if (manager != null && !retryChannel) {
  152. Toast.makeText(this, "Channel lost. Trying again", Toast.LENGTH_LONG).show();
  153. resetData();
  154. retryChannel = true;
  155. manager.initialize(this, getMainLooper(), this);
  156. } else {
  157. Toast.makeText(this,
  158. "Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",Toast.LENGTH_LONG).show();
  159. }
  160. }
  161.  
  162. public void cancelDisconnect() {
  163. if (manager != null) {
  164. final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager().findFragmentById(R.id.frag_list);
  165. if (fragment.getDevice() == null
  166. || fragment.getDevice().status == WifiP2pDevice.CONNECTED) {
  167. disconnect();
  168. } else if (fragment.getDevice().status == WifiP2pDevice.AVAILABLE || fragment.getDevice().status == WifiP2pDevice.INVITED) {
  169. manager.cancelConnect(channel, new ActionListener() {
  170. public void onSuccess() {
  171. Toast.makeText(WIFIDirectDemoActivity.this, "Aborting connection", Toast.LENGTH_SHORT).show();
  172. }
  173.  
  174. public void onFailure(int reasonCode) {
  175. Toast.makeText(WIFIDirectDemoActivity.this,
  176. "Connect abort request failed. Reason Code: " + reasonCode, Toast.LENGTH_SHORT).show();
  177. }
  178. });
  179. }
  180. }
  181. }
  182. }
WiFiDirectBroadcastReceiver.java 的代码如下:
  1. package introduction.android.wifidirectdemo;
  2.  
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.net.NetworkInfo;
  7. import android.net.wifi.p2p.WifiP2pDevice;
  8. import android.net.wifi.p2p.WifiP2pManager;
  9. import android.net.wifi.p2p.WifiP2pManager.Channel;
  10. import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
  11. import android.util.Log;
  12.  
  13. public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
  14. private WifiP2pManager manager;
  15. private Channel channel;
  16. private WIFIDirectDemoActivity activity;
  17.  
  18. public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel, WIFIDirectDemoActivity wifiDirectDemoActivity) {
  19. super();
  20. this.manager = manager;
  21. this.channel = channel;
  22. this.activity = wifiDirectDemoActivity;
  23. }
  24.  
  25. @Override
  26. public void onReceive(Context context, Intent intent) {
  27. String action = intent.getAction();
  28. if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
  29. // UI update to indicate wifi p2p status.
  30. int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
  31. if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
  32. // Wifi Direct mode is enabled activity.setlsWifiP2pEnabled (true) ;
  33. } else {
  34. activity.setIsWifiP2pEnabled(false);
  35. activity.resetData();
  36. }
  37. Log.d(WIFIDirectDemoActivity.TAG, "P2P state changed - " + state);
  38. } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
  39. // request available peers from the wifi p2p manager. This is an
  40. // asynchronous call and the calling activity is notified with a
  41. // callback on PeerListListener.onPeersAvailable() if (manager !=null) {
  42. manager.requestPeers(channel, (PeerListListener) activity.getFragmentManager().findFragmentById(R.id.frag_list));
  43. Log.d(WIFIDirectDemoActivity.TAG, "P2P peers changed");
  44. } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
  45. if (manager == null) {
  46. return;
  47. }
  48. NetworkInfo networkInfo = (NetworkInfo) intent
  49. .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
  50. if (networkInfo.isConnected()) {
  51. // we are connected with the other device, request connection
  52. // info to find group owner IP
  53. DeviceDetailFragment1 fragment = (DeviceDetailFragmentl) activity.getFragmentManager().findFragmentById(R.id.frag_detail);
  54. manager.requestConnectionlnfo(channel, fragment);
  55. } else {
  56. // It's a disconnect
  57. activity.resetData();
  58. }
  59. } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)){
  60. DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
  61. .findFragmentById(R.id.frag_list);
  62. fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
  63. WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
  64. }
  65. }
  66. }
DeviceListFragment.java 的代码如下:
  1. package introduction.android.wifidirectdemo;
  2.  
  3.  
  4. import android.app.ListFragment;
  5. import android.app.ProgressDialog;
  6. import android.content.Context;
  7. import android.content.DialogInterface;
  8. import android.net.wifi.p2p.WifiP2pConfig;
  9. import android.net.wifi.p2p.WifiP2pDevice;
  10. import android.net.wifi.p2p.WifiP2pDeviceList;
  11. import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
  12. import android.os.Bundle;
  13. import android.util.Log;
  14. import android.view.LayoutInflater;
  15. import android.view.View;
  16. import android.view.ViewGroup;
  17. import android.widget.ArrayAdapter;
  18. import android.widget.ListView;
  19. import android.widget.TextView;
  20.  
  21. import java.util.ArrayList;
  22. import java.util.List;
  23.  
  24. public class DeviceListFragment extends ListFragment implements PeerListListener {
  25. private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
  26. ProgressDialog progressDialog = null;
  27. View mContentView = null;
  28. private WifiP2pDevice device;
  29.  
  30. @Override
  31. public void onActivityCreated(Bundle savedInstanceState) {
  32. super.onActivityCreated(savedInstanceState);
  33. this.setListAdapter(new WiFiPeerListAdapter(getActivity(), R.layout.row_devices,
  34. peers));
  35. }
  36.  
  37. @Override
  38. public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
  39. savedInstanceState) {
  40. mContentView = inflater.inflate(R.layout.device_list, null);
  41. return mContentView;
  42. }
  43.  
  44. /* return this device */
  45. public WifiP2pDevice getDevice() {
  46. return device;
  47. }
  48.  
  49. private static String getDeviceStatus(int deviceStatus) {
  50. Log.d(WIFIDirectDemoActivity.TAG, "Peer status :" + deviceStatus);
  51. switch (deviceStatus) {
  52. case WifiP2pDevice.AVAILABLE:
  53. return "Available";
  54. case WifiP2pDevice.INVITED:
  55. return "Invited";
  56. case WifiP2pDevice.CONNECTED:
  57. return "Connected";
  58. case WifiP2pDevice.FAILED:
  59. return "Failed";
  60. case WifiP2pDevice.UNAVAILABLE:
  61. return "Unavailable";
  62. default:
  63. return "Unknown";
  64. }
  65. }
  66.  
  67. /**
  68. * Initiate a connection with the peer.
  69. */
  70. @Override
  71. public void onListItemClick(ListView l, View v, int position, long id) {
  72. WifiP2pDevice device = (WifiP2pDevice) getListAdapter().getItem(position);
  73. ((DeviceActionListener) getActivity()).showDetails(device);
  74. }
  75.  
  76. /*
  77. Array adapter for ListFragment that maintains WifiP2pDevice list.
  78. */
  79. public class WiFiPeerListAdapter extends ArrayAdapter<WifiP2pDevice> {
  80. private List<WifiP2pDevice> items;
  81.  
  82. public WiFiPeerListAdapter(Context context, int textViewResourceId, List<WifiP2pDevice> objects) {
  83. super(context, textViewResourceId, objects);
  84. items = objects;
  85. }
  86.  
  87. @Override
  88. public View getView(int position, View convertView, ViewGroup parent) {
  89. View v = convertView;
  90. if (v == null) {
  91. LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  92. v = vi.inflate(R.layout.row_devices, null);
  93. }
  94. WifiP2pDevice device = items.get(position);
  95. if (device != null) {
  96. TextView top = (TextView) v.findViewById(R.id.device_name);
  97. TextView bottom = (TextView) v.findViewById(R.id.device_details);
  98. if (top != null) {
  99. top.setText(device.deviceName);
  100. }
  101. if (bottom != null) {
  102. bottom.setText(getDeviceStatus(device.status));
  103. }
  104. }
  105. return v;
  106. }
  107.  
  108. public void updateThisDevice(WifiP2pDevice device) {
  109. this.device = device;
  110. TextView view = (TextView) mContentView.findViewById(R.id.my_name);
  111. view.setText(device.deviceName);
  112. view = (TextView) mContentView.findViewById(R.id.my_status);
  113. view.setText(getDeviceStatus(device.status));
  114. }
  115.  
  116. public void onPeersAvailable(WifiP2pDeviceList peerList) {
  117. if (progressDialog != null && progressDialog.isShowing()) {
  118. progressDialog.dismiss();
  119. }
  120. peers.clear();
  121. peers.addAll(peerList.getDeviceList());
  122. ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
  123. if (peers.size() == 0) {
  124. Log.d(WIFIDirectDemoActivity.TAG, "No devices found");
  125. return;
  126. }
  127. }
  128.  
  129. public void clearPeers() {
  130. peers.clear();
  131. ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
  132. }
  133.  
  134. public void onInitiateDiscovery() {
  135. if (progressDialog != null && progressDialog.isShowing()) {
  136. progressDialog.dismiss();
  137. }
  138. progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel", true,
  139. true, new DialogInterface.OnCancelListener() {
  140. public void onCancel(DialogInterface dialog) {
  141. }
  142. });
  143. }
  144.  
  145. public interface DeviceActionListener {
  146. void showDetails(WifiP2pDevice device);
  147.  
  148. void cancelDisconnect();
  149.  
  150. void connect(WifiP2pConfig config);
  151.  
  152. void disconnect();
  153. }
  154. }
  155. }
FileTransferService.java 的代码如下:
  1. package introduction.android.wifidirectdemo;
  2.  
  3. import android.app.IntentService;
  4. import android.content.ContentResolver;
  5. import android.content.Context;
  6. import android.content.Intent;
  7. import android.net.Uri;
  8. import android.util.Log;
  9.  
  10. import java.io.FileNotFoundException;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.OutputStream;
  14. import java.net.InetSocketAddress;
  15. import java.net.Socket;
  16.  
  17. public class FileTransferService extends IntentService {
  18. private static final int SOCKET_TIMEOUT = 5000;
  19. public static final String ACTION_SEND_FILE = "com.example.android.wifidirect.SEND_FILE"
  20. public static final String EXTRAS_FILE_PATH = "file_url";
  21. public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
  22. public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";
  23.  
  24. public FileTransferService(String name) {
  25. super(name);
  26. }
  27.  
  28. public FileTransferService() {
  29. super("FileTransferService");
  30. }
  31.  
  32. @Override
  33. protected void onHandleIntent(Intent intent) {
  34. Context context = getApplicationContext();
  35. if (intent.getAction().equals(ACTION_SEND_FILE)) {
  36. String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
  37. String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
  38. Socket socket = new Socket();
  39. int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
  40. try {
  41. Log.d(WIFIDirectDemoActivity.TAG, "Opening client socket - ");
  42. socket.bind(null);
  43. socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
  44. Log.d(WIFIDirectDemoActivity.TAG, "Client socket - " + socket.isConnected())
  45. OutputStream stream = socket.getOutputStream();
  46. ContentResolver cr = context.getContentResolver();
  47. InputStream is = null;
  48. try {
  49. is = cr.openInputStream(Uri.parse(fileUri));
  50. } catch (FileNotFoundException e) {
  51. Log.d(WIFIDirectDemoActivity.TAG, e.toString());
  52. }
  53. DeviceDetailFragment1.copyFile(is, stream);
  54. Log.d(WIFIDirectDemoActivity.TAG, "Client: Data written");
  55. } catch (IOException e) {
  56. Log.e(WIFIDirectDemoActivity.TAG, e.getMessage());
  57. } finally {
  58. if (socket != null) {
  59. if (socket.isConnected()) {
  60. try {
  61. socket.close();
  62. } catch (IOException e) {
  63. // Give up
  64. e.printStackTrace();
  65. }
  66. }
  67. }
  68. }
  69. }
  70. }
  71. }