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