1 
2 package com.example.android.wifidirect.discovery;
3 
4 import android.app.Activity;
5 import android.app.Fragment;
6 import android.content.BroadcastReceiver;
7 import android.content.Context;
8 import android.content.IntentFilter;
9 import android.net.wifi.WpsInfo;
10 import android.net.wifi.p2p.WifiP2pConfig;
11 import android.net.wifi.p2p.WifiP2pDevice;
12 import android.net.wifi.p2p.WifiP2pInfo;
13 import android.net.wifi.p2p.WifiP2pManager;
14 import android.net.wifi.p2p.WifiP2pManager.ActionListener;
15 import android.net.wifi.p2p.WifiP2pManager.Channel;
16 import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
17 import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
18 import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
19 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
20 import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
21 import android.os.Bundle;
22 import android.os.Handler;
23 import android.os.Message;
24 import android.util.Log;
25 import android.view.View;
26 import android.widget.TextView;
27 
28 import com.example.android.wifidirect.discovery.WiFiChatFragment.MessageTarget;
29 import com.example.android.wifidirect.discovery.WiFiDirectServicesList.DeviceClickListener;
30 import com.example.android.wifidirect.discovery.WiFiDirectServicesList.WiFiDevicesAdapter;
31 
32 import java.io.IOException;
33 import java.util.HashMap;
34 import java.util.Map;
35 
36 /**
37  * The main activity for the sample. This activity registers a local service and
38  * perform discovery over Wi-Fi p2p network. It also hosts a couple of fragments
39  * to manage chat operations. When the app is launched, the device publishes a
40  * chat service and also tries to discover services published by other peers. On
41  * selecting a peer published service, the app initiates a Wi-Fi P2P (Direct)
42  * connection with the peer. On successful connection with a peer advertising
43  * the same service, the app opens up sockets to initiate a chat.
44  * {@code WiFiChatFragment} is then added to the the main activity which manages
45  * the interface and messaging needs for a chat session.
46  */
47 public class WiFiServiceDiscoveryActivity extends Activity implements
48         DeviceClickListener, Handler.Callback, MessageTarget,
49         ConnectionInfoListener {
50 
51     public static final String TAG = "wifidirectdemo";
52 
53     // TXT RECORD properties
54     public static final String TXTRECORD_PROP_AVAILABLE = "available";
55     public static final String SERVICE_INSTANCE = "_wifidemotest";
56     public static final String SERVICE_REG_TYPE = "_presence._tcp";
57 
58     public static final int MESSAGE_READ = 0x400 + 1;
59     public static final int MY_HANDLE = 0x400 + 2;
60     private WifiP2pManager manager;
61 
62     static final int SERVER_PORT = 4545;
63 
64     private final IntentFilter intentFilter = new IntentFilter();
65     private Channel channel;
66     private BroadcastReceiver receiver = null;
67     private WifiP2pDnsSdServiceRequest serviceRequest;
68 
69     private Handler handler = new Handler(this);
70     private WiFiChatFragment chatFragment;
71     private WiFiDirectServicesList servicesList;
72 
73     private TextView statusTxtView;
74 
getHandler()75     public Handler getHandler() {
76         return handler;
77     }
78 
setHandler(Handler handler)79     public void setHandler(Handler handler) {
80         this.handler = handler;
81     }
82 
83     /** Called when the activity is first created. */
84     @Override
onCreate(Bundle savedInstanceState)85     public void onCreate(Bundle savedInstanceState) {
86         super.onCreate(savedInstanceState);
87         setContentView(R.layout.main);
88         statusTxtView = (TextView) findViewById(R.id.status_text);
89 
90         intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
91         intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
92         intentFilter
93                 .addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
94         intentFilter
95                 .addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
96 
97         manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
98         channel = manager.initialize(this, getMainLooper(), null);
99         startRegistrationAndDiscovery();
100 
101         servicesList = new WiFiDirectServicesList();
102         getFragmentManager().beginTransaction()
103                 .add(R.id.container_root, servicesList, "services").commit();
104 
105     }
106 
107     @Override
onRestart()108     protected void onRestart() {
109         Fragment frag = getFragmentManager().findFragmentByTag("services");
110         if (frag != null) {
111             getFragmentManager().beginTransaction().remove(frag).commit();
112         }
113         super.onRestart();
114     }
115 
116     @Override
onStop()117     protected void onStop() {
118         if (manager != null && channel != null) {
119             manager.removeGroup(channel, new ActionListener() {
120 
121                 @Override
122                 public void onFailure(int reasonCode) {
123                     Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
124                 }
125 
126                 @Override
127                 public void onSuccess() {
128                 }
129 
130             });
131         }
132         super.onStop();
133     }
134 
135     /**
136      * Registers a local service and then initiates a service discovery
137      */
startRegistrationAndDiscovery()138     private void startRegistrationAndDiscovery() {
139         Map<String, String> record = new HashMap<String, String>();
140         record.put(TXTRECORD_PROP_AVAILABLE, "visible");
141 
142         WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
143                 SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
144         manager.addLocalService(channel, service, new ActionListener() {
145 
146             @Override
147             public void onSuccess() {
148                 appendStatus("Added Local Service");
149             }
150 
151             @Override
152             public void onFailure(int error) {
153                 appendStatus("Failed to add a service");
154             }
155         });
156 
157         discoverService();
158 
159     }
160 
discoverService()161     private void discoverService() {
162 
163         /*
164          * Register listeners for DNS-SD services. These are callbacks invoked
165          * by the system when a service is actually discovered.
166          */
167 
168         manager.setDnsSdResponseListeners(channel,
169                 new DnsSdServiceResponseListener() {
170 
171                     @Override
172                     public void onDnsSdServiceAvailable(String instanceName,
173                             String registrationType, WifiP2pDevice srcDevice) {
174 
175                         // A service has been discovered. Is this our app?
176 
177                         if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
178 
179                             // update the UI and add the item the discovered
180                             // device.
181                             WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
182                                     .findFragmentByTag("services");
183                             if (fragment != null) {
184                                 WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
185                                         .getListAdapter());
186                                 WiFiP2pService service = new WiFiP2pService();
187                                 service.device = srcDevice;
188                                 service.instanceName = instanceName;
189                                 service.serviceRegistrationType = registrationType;
190                                 adapter.add(service);
191                                 adapter.notifyDataSetChanged();
192                                 Log.d(TAG, "onBonjourServiceAvailable "
193                                         + instanceName);
194                             }
195                         }
196 
197                     }
198                 }, new DnsSdTxtRecordListener() {
199 
200                     /**
201                      * A new TXT record is available. Pick up the advertised
202                      * buddy name.
203                      */
204                     @Override
205                     public void onDnsSdTxtRecordAvailable(
206                             String fullDomainName, Map<String, String> record,
207                             WifiP2pDevice device) {
208                         Log.d(TAG,
209                                 device.deviceName + " is "
210                                         + record.get(TXTRECORD_PROP_AVAILABLE));
211                     }
212                 });
213 
214         // After attaching listeners, create a service request and initiate
215         // discovery.
216         serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
217         manager.addServiceRequest(channel, serviceRequest,
218                 new ActionListener() {
219 
220                     @Override
221                     public void onSuccess() {
222                         appendStatus("Added service discovery request");
223                     }
224 
225                     @Override
226                     public void onFailure(int arg0) {
227                         appendStatus("Failed adding service discovery request");
228                     }
229                 });
230         manager.discoverServices(channel, new ActionListener() {
231 
232             @Override
233             public void onSuccess() {
234                 appendStatus("Service discovery initiated");
235             }
236 
237             @Override
238             public void onFailure(int arg0) {
239                 appendStatus("Service discovery failed");
240 
241             }
242         });
243     }
244 
245     @Override
connectP2p(WiFiP2pService service)246     public void connectP2p(WiFiP2pService service) {
247         WifiP2pConfig config = new WifiP2pConfig();
248         config.deviceAddress = service.device.deviceAddress;
249         config.wps.setup = WpsInfo.PBC;
250         if (serviceRequest != null)
251             manager.removeServiceRequest(channel, serviceRequest,
252                     new ActionListener() {
253 
254                         @Override
255                         public void onSuccess() {
256                         }
257 
258                         @Override
259                         public void onFailure(int arg0) {
260                         }
261                     });
262 
263         manager.connect(channel, config, new ActionListener() {
264 
265             @Override
266             public void onSuccess() {
267                 appendStatus("Connecting to service");
268             }
269 
270             @Override
271             public void onFailure(int errorCode) {
272                 appendStatus("Failed connecting to service");
273             }
274         });
275     }
276 
277     @Override
handleMessage(Message msg)278     public boolean handleMessage(Message msg) {
279         switch (msg.what) {
280             case MESSAGE_READ:
281                 byte[] readBuf = (byte[]) msg.obj;
282                 // construct a string from the valid bytes in the buffer
283                 String readMessage = new String(readBuf, 0, msg.arg1);
284                 Log.d(TAG, readMessage);
285                 (chatFragment).pushMessage("Buddy: " + readMessage);
286                 break;
287 
288             case MY_HANDLE:
289                 Object obj = msg.obj;
290                 (chatFragment).setChatManager((ChatManager) obj);
291 
292         }
293         return true;
294     }
295 
296     @Override
onResume()297     public void onResume() {
298         super.onResume();
299         receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
300         registerReceiver(receiver, intentFilter);
301     }
302 
303     @Override
onPause()304     public void onPause() {
305         super.onPause();
306         unregisterReceiver(receiver);
307     }
308 
309     @Override
onConnectionInfoAvailable(WifiP2pInfo p2pInfo)310     public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo) {
311         Thread handler = null;
312         /*
313          * The group owner accepts connections using a server socket and then spawns a
314          * client socket for every client. This is handled by {@code
315          * GroupOwnerSocketHandler}
316          */
317 
318         if (p2pInfo.isGroupOwner) {
319             Log.d(TAG, "Connected as group owner");
320             try {
321                 handler = new GroupOwnerSocketHandler(
322                         ((MessageTarget) this).getHandler());
323                 handler.start();
324             } catch (IOException e) {
325                 Log.d(TAG,
326                         "Failed to create a server thread - " + e.getMessage());
327                 return;
328             }
329         } else {
330             Log.d(TAG, "Connected as peer");
331             handler = new ClientSocketHandler(
332                     ((MessageTarget) this).getHandler(),
333                     p2pInfo.groupOwnerAddress);
334             handler.start();
335         }
336         chatFragment = new WiFiChatFragment();
337         getFragmentManager().beginTransaction()
338                 .replace(R.id.container_root, chatFragment).commit();
339         statusTxtView.setVisibility(View.GONE);
340     }
341 
appendStatus(String status)342     public void appendStatus(String status) {
343         String current = statusTxtView.getText().toString();
344         statusTxtView.setText(current + "\n" + status);
345     }
346 }
347