Wifi-Direct

参考链接:http://developer.android.com/guide/topics/connectivity/wifip2p.html

国内镜像开发文档:http://wear.techbrood.com/guide/topics/connectivity/wifip2p.html

 

API:

WifiP2pManager类提供了很多方法允许用户通过设备的Wi-Fi模块来进行交互,比如做一些如发现,连接其他对等设备的事情。下列的方法都是可以使用的: 表格1.Wi-Fi直连技术方法

方法名详细描述

initialize()

通过Wi-Fi框架对应用来进行注册。这个方法必须在任何其他Wi-Fi直连方法使用之前调用。

connect()]

开始一个拥有特定设置的设备的点对点连接。

cancelConnect()

取消任何一个正在进行的点对点组的连接。

requestConnectInfo()

获取一个设备的连接信息。

createGroup()

以当前设备为组拥有者来创建一个点对点连接组。

removeGroup()

移除当前的点对点连接组。

requestGroupInfo()

获取点对点连接组的信息。

discoverPeers()

初始化对等设备的发现。

requestPeers()

获取当前发现的对等设备列表。

WifiP2pManager的方法可以让你在一个监听器里传递参数,这样Wi-fi直连框架就可以通知给你的窗体这个方法调用的状态。可以被使用的监听器接口和使用监听器的相应的WifiP2pManager的方法的调用都将在下面这张表中有所描述:

表格 2. Wi-Fi直连监听器方法

监听器接口相关联的方法

WifiP2pManager.ActionListener

connect(), cancelConnect(), createGroup(), removeGroup(), and discoverPeers()

WifiP2pManager.ChannelListener

initialize()

WifiP2pManager.ConnectionInfoListener

requestConnectInfo()

WifiP2pManager.GroupInfoListener

requestGroupInfo()

WifiP2pManager.PeerListListener

requestPeers()

Wi-Fi直连技术的API定义了一些当特定的Wi-Fi直连事件发生时作为广播的意图,比如说当一个新的对等设备被发现,或者一个设备的Wi-Fi状态的改变。你可以在你的应用里通过创建一个处理这些意图的广播接收器来注册去接收这些意图。

Table 3. Wi-Fi 直连意图

意图名称详细描述

WIFI_P2P_CONNECTION_CHANGED_ACTION

当设备的Wi-Fi连接信息状态改变时候进行广播。

WIFI_P2P_PEERS_CHANGED_ACTION

当调用discoverPeers()方法的时候进行广播。在你的应用里处理此意图时,你通常会调用requestPeers()去获得对等设备列表的更新。

WIFI_P2P_STATE_CHANGED_ACTION

当设备的Wi-Fi 直连功能打开或关闭时进行广播。

WIFI_P2P_THIS_DEVICE_CHANGED_ACTION

当设备的详细信息改变的时候进行广播,比如设备的名称

 

创建一个广播接收器

一个广播接收器允许你接收由android系统发布的意图广播,这样你的应用就可以对那些你感兴趣的事件作出响应。创建一个基本的Wi-Fi直连意图使用的广播接收器的步骤如下:

1.创建一个继承自BroadcastReceiver的类。对于类的构造,一般最常用的就是以WifiP2pManager, WifiP2pManager.Channel作为参数,同时这个广播接收器对应的窗体也将被注册进来。这个广播接收器可以像窗体发送更新或者在需要的时候可以访问Wi-Fi硬件或通信通道。

2.在广播接收器里,处理onReceive()方法里你感兴趣的意图。执行接收到的意图的任何需要的动作。比如,广播接收器接收到一个WIFI_P2P_PEERS_CHANGED_ACTION的意图,你就要调用requestPeers()方法去获得当前发现的对等设备列表。

下面的代码展示了怎样去创建一个典型的广播接收器。广播接收器接收一个WifiP2pManager对象和一个窗体对象作为参数然后利用这两个类去处理接收到的意图的特定的动作需求。

 

 1 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
 2 @SuppressLint("NewApi")
 3 public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
 4 
 5     private WifiP2pManager manager;
 6     private Channel channel;
 7     private WiFiDirectActivity activity;
 8 
 9 
10     public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
11             WiFiDirectActivity activity) {
12         super();
13         this.manager = manager;
14         this.channel = channel;
15         this.activity = activity;
16     }
17 
18 
19     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
20     @SuppressLint("NewApi")
21     @Override
22     public void onReceive(Context context, Intent intent) {
23         String action = intent.getAction();
24         if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
25             int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
26             if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
27             } else {
28                 Log.d(WiFiDirectActivity.TAG, "无法使用Wifi-Direct");
29                 activity.setIsWifiP2pEnabled(false);
30                 activity.resetData();
31 
32             }
33             Log.d(WiFiDirectActivity.TAG, "P2P state changed - " + state);
34         } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
35             if (manager != null) {
36                 manager.requestPeers(channel, (PeerListListener) activity.getFragmentManager()
37                         .findFragmentById(R.id.frag_list));
38             }
39             Log.d(WiFiDirectActivity.TAG, "P2P peers changed");
40         } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
41             if (manager == null) {
42                 return;
43             }
44 
45             NetworkInfo networkInfo = (NetworkInfo) intent
46                     .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
47 
48             if (networkInfo.isConnected()) {
49 
50                 // we are connected with the other device, request connection
51                 // info to find group owner IP
52 
53                 DeviceDetailFragment fragment = (DeviceDetailFragment) activity
54                         .getFragmentManager().findFragmentById(R.id.frag_detail);
55                 manager.requestConnectionInfo(channel, fragment);
56             } else {
57                 // It's a disconnect
58                 activity.resetData();
59             }
60         } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
61             DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
62                     .findFragmentById(R.id.frag_list);
63             fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
64                     WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
65 
66         }
67     }
68 }

 

发现对等设备

要发现可以使用并连接的对等设备,调用discoverPeers()方法去检测在范围内的可使用设备。这个方法的调用是异步的同时如果你创建了一个WifiP2pManager.ActionListener监听器的话你会通过onSuccess()或者onFailure()方法收到发现成功或失败的消息。

onSuccess()方法只能通知你发现的过程是否成功而不能提供任何关于发现设备的信息:

 1 manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
 2     @Override
 3     public void onSuccess() {
 4         ...
 5     }
 6  
 7     @Override
 8     public void onFailure(int reasonCode) {
 9         ...
10     }
11 });

连接到设备

当你已经找到你要连接的设备在获得发现设备列表之后,调用connect()方法去连接指定设备。这个方法的调用需要一个包含待连接设备信息的WifiP2pConfig对象。你可以通过WifiP2pManager.ActionListener接收到连接是否成功的通知。下面的代码展示了怎样去连接一个想得到的连接:

 1 WifiP2pDevice device;
 2 WifiP2pConfig config = new WifiP2pConfig();
 3 config.deviceAddress = device.deviceAddress;
 4 manager.connect(channel, config, new ActionListener() {
 5  
 6     @Override
 7     public void onSuccess() {
 8         //success logic
 9     }
10  
11     @Override
12     public void onFailure(int reason) {
13         //failure logic
14     }
15 });

 

 

创建一个Wi-Fi直连的应用

创建一个Wi-Fi直连的应用包括创建和注册一个广播接收器,发现其他设备,连接其他设备,然后传输数据等步骤。接下来的几个部分描述了怎么去做这些工作。

初始化设置

在使用Wi-Fi直连的API之前,你必须确保你的应用可以访问设备的硬件并且你的设备要支持Wi-Fi直连的通讯协议。如果Wi-Fi直连技术是支持的,你可以获得一个WifiP2pManager的实例对象,然后创建并注册你的广播接收器,然后开始使用Wi-Fi直连的API方法。

1.为设备的Wi-Fi硬件获取权限并在Android的清单文件中声明你的应用正确使用的最低SDK版本:

1 <uses-sdk android:minSdkVersion="14" />
2 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
3 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
4 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
5 <uses-permission android:name="android.permission.INTERNET" />
6 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

2.在你的窗体的onCreate()方法里,获得一个WifiP2pManager的实例并调用initialize()方法通过Wi-Fi直连框架去注册你的应用。这个方法返回一个WifiP2pManager.Channel对象,是被用来连接你的应用和Wi-Fi直连框架的。你应该再创建一个以WifiP2pManager和WifiP2pManager.Channel为参数且关联你的窗体的广播接收器的实例。这样你的广播接收器就可以接收到你感兴趣的事件去通知你的窗体并更新它。它还可以让你在需要的时候操纵设备的Wi-Fi状态。

 1 WifiP2pManager mManager;
 2 Channel mChannel;
 3 BroadcastReceiver mReceiver;
 4 ...
 5 @Override
 6 protected void onCreate(Bundle savedInstanceState){
 7     ...
 8     mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
 9     mChannel = mManager.initialize(this, getMainLooper(), null);
10     mReceiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
11     ...
12 }

3.创建一个意图过滤器并把它添加在你的广播接收器需要处理的意图上。

 1 IntentFilter mIntentFilter;
 2 ...
 3 @Override
 4 protected void onCreate(Bundle savedInstanceState){
 5     ...
 6     mIntentFilter = new IntentFilter();
 7     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
 8     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
 9     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
10     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
11     ...
12 }

4.注册你的广播接收器在窗体的onResume()方法,解除注册在onPause()方法中。

 1 @Override
 2 protected void onResume() {
 3     super.onResume();
 4     registerReceiver(mReceiver, mIntentFilter);
 5 }
 6 /* unregister the broadcast receiver */
 7 @Override
 8 protected void onPause() {
 9     super.onPause();
10     unregisterReceiver(mReceiver);
11 }

当你获取到一个WifiP2pManager.Channel对象并且设置好你的广播接收器时,你的应用就可以调用Wi-Fi直连的方法并且可以接收Wi-Fi直连的意图。

你可以现在就通过调用WifiP2pManager中的方法取实现你的应用体验Wi-Fi直连技术的特性了。

 

下面是窗体Activity的完整代码:

  1 @SuppressLint("NewApi")
  2 public class WiFiDirectActivity extends Activity implements ChannelListener, DeviceActionListener {
  3 
  4     public static final String TAG = "wifidirectdemo";
  5     private WifiP2pManager manager;
  6     private boolean isWifiP2pEnabled = false;
  7     private boolean retryChannel = false;
  8 
  9     private final IntentFilter intentFilter = new IntentFilter();
 10     private Channel channel;
 11     private BroadcastReceiver receiver = null;
 12 
 13     public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
 14         this.isWifiP2pEnabled = isWifiP2pEnabled;
 15     }
 16 
 17     @Override
 18     public void onCreate(Bundle savedInstanceState) {
 19         super.onCreate(savedInstanceState);
 20         setContentView(R.layout.main);
 21 
 22         // add necessary intent values to be matched.
 23 
 24         intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
 25         intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
 26         intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
 27         intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
 28 
 29         manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
 30         channel = manager.initialize(this, getMainLooper(), null);
 31     }
 32 
 33     /** register the BroadcastReceiver with the intent values to be matched */
 34     @Override
 35     public void onResume() {
 36         super.onResume();
 37         receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
 38         registerReceiver(receiver, intentFilter);
 39     }
 40 
 41     @Override
 42     public void onPause() {
 43         super.onPause();
 44         unregisterReceiver(receiver);
 45     }
 46 
 47     /**
 48      * Remove all peers and clear all fields. This is called on
 49      * BroadcastReceiver receiving a state change event.
 50      */
 51     public void resetData() {
 52         DeviceListFragment fragmentList = (DeviceListFragment) getFragmentManager()
 53                 .findFragmentById(R.id.frag_list);
 54         DeviceDetailFragment fragmentDetails = (DeviceDetailFragment) getFragmentManager()
 55                 .findFragmentById(R.id.frag_detail);
 56         if (fragmentList != null) {
 57             fragmentList.clearPeers();
 58         }
 59         if (fragmentDetails != null) {
 60             fragmentDetails.resetViews();
 61         }
 62     }
 63 
 64     @Override
 65     public boolean onCreateOptionsMenu(Menu menu) {
 66         MenuInflater inflater = getMenuInflater();
 67         inflater.inflate(R.menu.wi_fi_direct, menu);
 68         return true;
 69     }
 70 
 71     @Override
 72     public boolean onOptionsItemSelected(MenuItem item) {
 73         switch (item.getItemId()) {
 74             case R.id.atn_direct_enable:
 75                 if (manager != null && channel != null) {
 76 
 77                     // Since this is the system wireless settings activity, it's
 78                     // not going to send us a result. We will be notified by
 79                     // WiFiDeviceBroadcastReceiver instead.
 80 
 81                     startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
 82                 } else {
 83                     Log.e(TAG, "channel or manager is null");
 84                 }
 85                 return true;
 86 
 87             case R.id.atn_direct_discover:
 88                 if (!isWifiP2pEnabled) {
 89                     Toast.makeText(WiFiDirectActivity.this, R.string.p2p_off_warning,
 90                             Toast.LENGTH_SHORT).show();
 91                     return true;
 92                 }
 93                 final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager()
 94                         .findFragmentById(R.id.frag_list);
 95                 fragment.onInitiateDiscovery();
 96                 manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
 97 
 98                     @Override
 99                     public void onSuccess() {
100                         Toast.makeText(WiFiDirectActivity.this, "Discovery Initiated",
101                                 Toast.LENGTH_SHORT).show();
102                     }
103 
104                     @Override
105                     public void onFailure(int reasonCode) {
106                         Toast.makeText(WiFiDirectActivity.this, "Discovery Failed : " + reasonCode,
107                                 Toast.LENGTH_SHORT).show();
108                     }
109                 });
110                 return true;
111             default:
112                 return super.onOptionsItemSelected(item);
113         }
114     }
115 
116     @Override
117     public void showDetails(WifiP2pDevice device) {
118         DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager()
119                 .findFragmentById(R.id.frag_detail);
120         fragment.showDetails(device);
121 
122     }
123 
124     @Override
125     public void connect(WifiP2pConfig config) {
126         manager.connect(channel, config, new ActionListener() {
127 
128             @Override
129             public void onSuccess() {
130                 // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
131                 Log.e(TAG, "Success!");
132             }
133 
134             @Override
135             public void onFailure(int reason) {
136                 Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
137                         Toast.LENGTH_SHORT).show();
138             }
139         });
140     }
141 
142     @Override
143     public void disconnect() {
144         final DeviceDetailFragment fragment = (DeviceDetailFragment) getFragmentManager()
145                 .findFragmentById(R.id.frag_detail);
146         fragment.resetViews();
147         manager.removeGroup(channel, new ActionListener() {
148 
149             @Override
150             public void onFailure(int reasonCode) {
151                 Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
152 
153             }
154 
155             @Override
156             public void onSuccess() {
157                 fragment.getView().setVisibility(View.GONE);
158             }
159 
160         });
161     }
162 
163     @Override
164     public void onChannelDisconnected() {
165         // we will try once more
166         if (manager != null && !retryChannel) {
167             Toast.makeText(this, "Channel lost. Trying again", Toast.LENGTH_LONG).show();
168             resetData();
169             retryChannel = true;
170             manager.initialize(this, getMainLooper(), this);
171         } else {
172             Toast.makeText(this,
173                     "Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",
174                     Toast.LENGTH_LONG).show();
175         }
176     }
177 
178     @Override
179     public void cancelDisconnect() {
180 
181         if (manager != null) {
182             final DeviceListFragment fragment = (DeviceListFragment) getFragmentManager()
183                     .findFragmentById(R.id.frag_list);
184             if (fragment.getDevice() == null
185                     || fragment.getDevice().status == WifiP2pDevice.CONNECTED) {
186                 disconnect();
187             } else if (fragment.getDevice().status == WifiP2pDevice.AVAILABLE
188                     || fragment.getDevice().status == WifiP2pDevice.INVITED) {
189 
190                 manager.cancelConnect(channel, new ActionListener() {
191 
192                     @Override
193                     public void onSuccess() {
194                         Toast.makeText(WiFiDirectActivity.this, "Aborting connection",
195                                 Toast.LENGTH_SHORT).show();
196                     }
197 
198                     @Override
199                     public void onFailure(int reasonCode) {
200                         Toast.makeText(WiFiDirectActivity.this,
201                                 "Connect abort request failed. Reason Code: " + reasonCode,
202                                 Toast.LENGTH_SHORT).show();
203                     }
204                 });
205             }
206         }
207 
208     }
209 }

显示设备连接的详细信息代码

  1 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  2 @SuppressLint("NewApi")
  3 public class DeviceListFragment extends ListFragment implements PeerListListener {
  4 
  5     private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
  6     ProgressDialog progressDialog = null;
  7     View mContentView = null;
  8     private WifiP2pDevice device;
  9 
 10     @Override
 11     public void onActivityCreated(Bundle savedInstanceState) {
 12         super.onActivityCreated(savedInstanceState);
 13         this.setListAdapter(new WiFiPeerListAdapter(getActivity(), R.layout.row_devices, peers));
 14 
 15     }
 16 
 17     @Override
 18     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 19         mContentView = inflater.inflate(R.layout.device_list, null);
 20         return mContentView;
 21     }
 22 
 23     public WifiP2pDevice getDevice() {
 24         return device;
 25     }
 26 
 27     private static String getDeviceStatus(int deviceStatus) {
 28         Log.d(WiFiDirectActivity.TAG, "Peer status :" + deviceStatus);
 29         switch (deviceStatus) {
 30             case WifiP2pDevice.AVAILABLE:
 31                 return "available";
 32             case WifiP2pDevice.INVITED:
 33                 return "invited";
 34             case WifiP2pDevice.CONNECTED:
 35                 return "connected";
 36             case WifiP2pDevice.FAILED:
 37                 return "failed";
 38             case WifiP2pDevice.UNAVAILABLE:
 39                 return "unavailable";
 40             default:
 41                 return "unknow";
 42 
 43         }
 44     }
 45 
 46     /**
 47      * Initiate a connection with the peer.
 48      */
 49     @Override
 50     public void onListItemClick(ListView l, View v, int position, long id) {
 51         WifiP2pDevice device = (WifiP2pDevice) getListAdapter().getItem(position);
 52         ((DeviceActionListener) getActivity()).showDetails(device);
 53     }
 54 
 55     /**
 56      * Array adapter for ListFragment that maintains WifiP2pDevice list.
 57      */
 58     private class WiFiPeerListAdapter extends ArrayAdapter<WifiP2pDevice> {
 59 
 60         private List<WifiP2pDevice> items;
 61 
 62         public WiFiPeerListAdapter(Context context, int textViewResourceId,
 63                 List<WifiP2pDevice> objects) {
 64             super(context, textViewResourceId, objects);
 65             items = objects;
 66 
 67         }
 68 
 69         @Override
 70         public View getView(int position, View convertView, ViewGroup parent) {
 71             View v = convertView;
 72             if (v == null) {
 73                 LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(
 74                         Context.LAYOUT_INFLATER_SERVICE);
 75                 v = vi.inflate(R.layout.row_devices, null);
 76             }
 77             WifiP2pDevice device = items.get(position);
 78             if (device != null) {
 79                 TextView top = (TextView) v.findViewById(R.id.device_name);
 80                 TextView bottom = (TextView) v.findViewById(R.id.device_details);
 81                 if (top != null) {
 82                     top.setText(device.deviceName);
 83                 }
 84                 if (bottom != null) {
 85                     bottom.setText(getDeviceStatus(device.status));
 86                 }
 87             }
 88 
 89             return v;
 90 
 91         }
 92     }
 93 
 94     public void updateThisDevice(WifiP2pDevice device) {
 95         this.device = device;
 96         TextView view = (TextView) mContentView.findViewById(R.id.my_name);
 97         view.setText(device.deviceName);
 98         view = (TextView) mContentView.findViewById(R.id.my_status);
 99         view.setText(getDeviceStatus(device.status));
100     }
101     
102     @Override
103     public void onPeersAvailable(WifiP2pDeviceList peerList) {
104         if (progressDialog != null && progressDialog.isShowing()) {
105             progressDialog.dismiss();
106         }
107         peers.clear();
108         peers.addAll(peerList.getDeviceList());
109       
110         if (peers.size() == 0) {
111             Log.d(WiFiDirectActivity.TAG, "size==0");
112             return;
113         }
114 
115     }
116 
117     public void clearPeers() {
118         peers.clear();
119         ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
120     }
121 
122     public void onInitiateDiscovery() {
123         if (progressDialog != null && progressDialog.isShowing()) {
124             progressDialog.dismiss();
125         }
126         progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel", "finding peers", true,
127                 true, new DialogInterface.OnCancelListener() {
128 
129                     @Override
130                     public void onCancel(DialogInterface dialog) {
131                         
132                     }
133                 });
134     }
135 
136     public interface DeviceActionListener {
137 
138         void showDetails(WifiP2pDevice device);
139 
140         void cancelDisconnect();
141 
142         void connect(WifiP2pConfig config);
143 
144         void disconnect();
145     }
146 
147 }

 

数据传输

一旦连接已经建立,你可以通过套接字来进行数据的传输。基本的数据传输步骤如下:

1.创建一个ServerSocket对象。这个服务端套接字对象等待一个来自指定地址和端口的客户端的连接且阻塞线程直到连接发生,所以把它建立在一个后台线程里。

2.创建一个客户端Socket.这个客户端套接字对象使用指定ip地址和端口去连接服务端设备。

3.服务端等待客户端的连接(使用accept()方法)。这个调用阻塞服务端线程直到客户端连接上,所以叫这个过程一个新的线程。当连接建立时,服务端可以接受来自客户端的数据。执行关于数据的任何动作,比如保存数据或者展示给用户。

 

 1      @Override
 2         protected String doInBackground(Void... params) {
 3             try {
 4                 ServerSocket serverSocket = new ServerSocket(8888);
 5                 //服务器端口号
 6                 Log.d(WiFiDirectActivity.TAG, "Server: Socket opened");
 7                 Socket client = serverSocket.accept();
 8                 //客户端绑定服务器端口
 9                 //!!!!!!!!!!使用accept方法等待客户机发送数据
10                 Log.d(WiFiDirectActivity.TAG, "Server: connection done");
11                 
12                 
13                 final File f = new File(Environment.getExternalStorageDirectory() + "/"
14                         + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
15                         + ".jpg");
16 
17                 File dirs = new File(f.getParent());
18                 if (!dirs.exists())
19                     dirs.mkdirs();
20                 f.createNewFile();
21 
22                 Log.d(WiFiDirectActivity.TAG, "server: copying files " + f.toString());
23                 InputStream inputstream = client.getInputStream();
24                 copyFile(inputstream, new FileOutputStream(f));
25                 serverSocket.close();
26                 return f.getAbsolutePath();
27             } catch (IOException e) {
28                 Log.e(WiFiDirectActivity.TAG, e.getMessage());
29                 return null;
30             }
31         }

4.服务端与客户端,官方demo只给出了客户端向服务端发送数据的方式。

 1 @Override
 2     public void onConnectionInfoAvailable(final WifiP2pInfo info) {
 3         if (progressDialog != null && progressDialog.isShowing()) {
 4             progressDialog.dismiss();
 5         }
 6         this.info = info;
 7         this.getView().setVisibility(View.VISIBLE);
 8 
 9         // The owner IP is now known.
10         TextView view = (TextView) mContentView.findViewById(R.id.group_owner);
11         view.setText(getResources().getString(R.string.group_owner_text)
12                 + ((info.isGroupOwner == true) ? getResources().getString(R.string.yes)
13                         : getResources().getString(R.string.no)));
14 
15         // InetAddress from WifiP2pInfo struct.
16         view = (TextView) mContentView.findViewById(R.id.device_info); 
17         view.setText("群主IP - " + info.groupOwnerAddress.getHostAddress());  
18 
19         // After the group negotiation, we assign the group owner as the file
20         // server. The file server is single threaded, single connection server
21         // socket.
22         if (info.groupFormed && info.isGroupOwner) {       
23             new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text))
24                  .execute();
25         } else if (info.groupFormed) {
26             mContentView.findViewById(R.id.btn_start_client).setVisibility(View.VISIBLE);
27             ((TextView) mContentView.findViewById(R.id.status_text)).setText(getResources()
28                     .getString(R.string.client_text));
29         }
30         
31         // hide the connect button
32         mContentView.findViewById(R.id.btn_connect).setVisibility(View.GONE);
33     }

 

完整代码如下:

  1 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  2 @SuppressLint("NewApi")
  3 public class DeviceDetailFragment extends Fragment implements ConnectionInfoListener {
  4 
  5     protected static final int CHOOSE_FILE_RESULT_CODE = 20;
  6     private View mContentView = null;
  7     private WifiP2pDevice device;
  8     private WifiP2pInfo info;
  9     ProgressDialog progressDialog = null;
 10 
 11     @Override
 12     public void onActivityCreated(Bundle savedInstanceState) {
 13         super.onActivityCreated(savedInstanceState);
 14     }
 15 
 16     @Override
 17     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 18 
 19         mContentView = inflater.inflate(R.layout.device_detail, null);
 20         mContentView.findViewById(R.id.btn_connect).setOnClickListener(new View.OnClickListener() {
 21 
 22             @Override
 23             public void onClick(View v) {
 24                 WifiP2pConfig config = new WifiP2pConfig();
 25                 config.deviceAddress = device.deviceAddress;
 26                 config.wps.setup = WpsInfo.PBC;
 27                 if (progressDialog != null && progressDialog.isShowing()) {
 28                     progressDialog.dismiss();
 29                 }
 30                 progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel",
 31                         "Connecting to :" + device.deviceAddress, true, true);
 32             }
 33         });
 34 
 35         mContentView.findViewById(R.id.btn_disconnect).setOnClickListener(
 36                 new View.OnClickListener() {
 37 
 38                     @Override
 39                     public void onClick(View v) {
 40                         ((DeviceActionListener) getActivity()).disconnect();
 41                     }
 42                 });
 43 
 44         mContentView.findViewById(R.id.btn_start_client).setOnClickListener(
 45                 new View.OnClickListener() {
 46 
 47                     @Override
 48                     public void onClick(View v) {
 49                         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
 50                         intent.setType("image/*");
 51                         startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
 52                     }
 53                 });
 54 
 55         return mContentView;
 56     }
 57 
 58     @Override
 59     public void onActivityResult(int requestCode, int resultCode, Intent data) {
 60 
 61         // User has picked an image. Transfer it to group owner i.e peer using
 62         // FileTransferService.
 63         Uri uri = data.getData();
 64         TextView statusText = (TextView) mContentView.findViewById(R.id.status_text);
 65         statusText.setText("Sending: " + uri);
 66         Log.d(WiFiDirectActivity.TAG, "Intent----------- " + uri);
 67         Intent serviceIntent = new Intent(getActivity(), FileTransferService.class);
 68         serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
 69         serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());
 70         serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
 71                 info.groupOwnerAddress.getHostAddress());
 72         serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8888);
 73         getActivity().startService(serviceIntent);
 74     }
 75 
 76     @Override
 77     public void onConnectionInfoAvailable(final WifiP2pInfo info) {
 78         if (progressDialog != null && progressDialog.isShowing()) {
 79             progressDialog.dismiss();
 80         }
 81         this.info = info;
 82         this.getView().setVisibility(View.VISIBLE);
 83 
 84         // The owner IP is now known.
 85         TextView view = (TextView) mContentView.findViewById(R.id.group_owner);
 86         view.setText(getResources().getString(R.string.group_owner_text)
 87                 + ((info.isGroupOwner == true) ? getResources().getString(R.string.yes)
 88                         : getResources().getString(R.string.no)));
 89 
 90         // InetAddress from WifiP2pInfo struct.
 91         view = (TextView) mContentView.findViewById(R.id.device_info); 
 92         view.setText("群主IP - " + info.groupOwnerAddress.getHostAddress());  
 93 
 94         // After the group negotiation, we assign the group owner as the file
 95         // server. The file server is single threaded, single connection server
 96         // socket.
 97         if (info.groupFormed && info.isGroupOwner) {       
 98             new FileServerAsyncTask(getActivity(), mContentView.findViewById(R.id.status_text))
 99                  .execute();
100         } else if (info.groupFormed) {
101             mContentView.findViewById(R.id.btn_start_client).setVisibility(View.VISIBLE);
102             ((TextView) mContentView.findViewById(R.id.status_text)).setText(getResources()
103                     .getString(R.string.client_text));
104         }
105         
106         // hide the connect button
107         mContentView.findViewById(R.id.btn_connect).setVisibility(View.GONE);
108     }
109 
110     /**
111      * Updates the UI with device data
112      * 
113      * @param device the device to be displayed
114      */
115     public void showDetails(WifiP2pDevice device) {
116         this.device = device;
117         this.getView().setVisibility(View.VISIBLE);
118         TextView view = (TextView) mContentView.findViewById(R.id.device_address);
119         view.setText(device.deviceAddress);
120         view = (TextView) mContentView.findViewById(R.id.device_info);
121         view.setText(device.toString());
122 
123     }
124 
125     /**
126      * Clears the UI fields after a disconnect or direct mode disable operation.
127      */
128     public void resetViews() {
129         mContentView.findViewById(R.id.btn_connect).setVisibility(View.VISIBLE);
130         TextView view = (TextView) mContentView.findViewById(R.id.device_address);
131         view.setText(R.string.empty);
132         view = (TextView) mContentView.findViewById(R.id.device_info);
133         view.setText(R.string.empty);
134         view = (TextView) mContentView.findViewById(R.id.group_owner);
135         view.setText(R.string.empty);
136         view = (TextView) mContentView.findViewById(R.id.status_text);
137         view.setText(R.string.empty);
138         mContentView.findViewById(R.id.btn_start_client).setVisibility(View.GONE);
139         this.getView().setVisibility(View.GONE);
140     }
141 
142     public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {
143 
144         private Context context;
145         private TextView statusText;
146 
147         public FileServerAsyncTask(Context context, View statusText) {
148             this.context = context;
149             this.statusText = (TextView) statusText;
150         }
151 
152         @Override
153         protected String doInBackground(Void... params) {
154             try {
155                 ServerSocket serverSocket = new ServerSocket(8888);
156                 //服务器端口号
157                 Log.d(WiFiDirectActivity.TAG, "Server: Socket opened");
158                 Socket client = serverSocket.accept();
159                 //客户端绑定服务器端
160                 //!!!!!!!!!!使用accept方法等待客户机发送数据
161                 Log.d(WiFiDirectActivity.TAG, "Server: connection done");
162                 
163                 
164                 final File f = new File(Environment.getExternalStorageDirectory() + "/"
165                         + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
166                         + ".jpg");
167 
168                 File dirs = new File(f.getParent());
169                 if (!dirs.exists())
170                     dirs.mkdirs();
171                 f.createNewFile();
172 
173                 Log.d(WiFiDirectActivity.TAG, "server: copying files " + f.toString());
174                 InputStream inputstream = client.getInputStream();
175                 copyFile(inputstream, new FileOutputStream(f));
176                 serverSocket.close();
177                 return f.getAbsolutePath();
178             } catch (IOException e) {
179                 Log.e(WiFiDirectActivity.TAG, e.getMessage());
180                 return null;
181             }
182         }
183 
184         @Override
185         protected void onPostExecute(String result) {
186             if (result != null) {
187                 statusText.setText("File copied - " + result);
188                 Intent intent = new Intent();
189                 intent.setAction(android.content.Intent.ACTION_VIEW);
190                 intent.setDataAndType(Uri.parse("file://" + result), "image/*");
191                 context.startActivity(intent);
192             }
193 
194         }
195 
196         @Override
197         protected void onPreExecute() {
198             statusText.setText("Opening a server socket");
199         }
200 
201     }
202 
203     public static boolean copyFile(InputStream inputStream, OutputStream out) {
204         byte buf[] = new byte[1024];
205         int len;
206         try {
207             while ((len = inputStream.read(buf)) != -1) {
208                 out.write(buf, 0, len);
209 
210             }
211             out.close();
212             inputStream.close();
213         } catch (IOException e) {
214             Log.d(WiFiDirectActivity.TAG, e.toString());
215             return false;
216         }
217         return true;
218     }
219 
220 }

文件传输代码如下:

 1 public class FileTransferService extends IntentService {
 2 
 3     private static final int SOCKET_TIMEOUT = 5000;
 4     public static final String ACTION_SEND_FILE = "com.example.android.wifidirect.SEND_FILE";
 5     public static final String EXTRAS_FILE_PATH = "file_url";
 6     public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
 7     public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";
 8 
 9     public FileTransferService(String name) {
10         super(name);
11     }
12 
13     public FileTransferService() {
14         super("FileTransferService");
15     }
16 
17     @Override
18     protected void onHandleIntent(Intent intent) {
19 
20         Context context = getApplicationContext();
21         if (intent.getAction().equals(ACTION_SEND_FILE)) {
22             String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
23             String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
24             Socket socket = new Socket();
25             int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
26          
27             try {
28                 Log.d(WiFiDirectActivity.TAG, "Opening client socket - ");
29                 socket.bind(null);
30                 socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
31 
32                 Log.d(WiFiDirectActivity.TAG, "Client socket - " + socket.isConnected());
33                 OutputStream stream = socket.getOutputStream();
34                 ContentResolver cr = context.getContentResolver();
35                 InputStream is = null;
36                 try {
37                     is = cr.openInputStream(Uri.parse(fileUri));
38                 } catch (FileNotFoundException e) {
39                     Log.d(WiFiDirectActivity.TAG, e.toString());
40                 }
41                 DeviceDetailFragment.copyFile(is, stream);
42                 Log.d(WiFiDirectActivity.TAG, "Client: Data written");
43             } catch (IOException e) {
44                 Log.e(WiFiDirectActivity.TAG, e.getMessage());
45             } finally {
46                 if (socket != null) {
47                     if (socket.isConnected()) {
48                         try {
49                             socket.close();
50                         } catch (IOException e) {
51                             // Give up
52                             e.printStackTrace();
53                         }
54                     }
55                 }
56             }
57 
58         }
59         
60     }
61 }

 

 

 

 

 

posted @ 2015-03-19 14:58  某某璀  阅读(2381)  评论(0编辑  收藏  举报
levels of contents