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