Skip to content

Instantly share code, notes, and snippets.

@Tulakshana
Last active January 21, 2019 17:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tulakshana/8b6b0b7d5d8d6658b444ba26a25600f6 to your computer and use it in GitHub Desktop.
Save Tulakshana/8b6b0b7d5d8d6658b444ba26a25600f6 to your computer and use it in GitHub Desktop.
Create peer-to-peer connections over Wi-Fi (Android). Explained in more detailed at https://the-useful.blogspot.com/2019/01/create-peer-to-peer-connections-over-wi.html
public class WDMainActivity extends AppCompatActivity implements WifiP2pManager.ConnectionInfoListener {
private static final String TAG = "WDMainActivity";
private static final String KEY_BUDDY_NAME = "buddyname";
private final IntentFilter intentFilter = new IntentFilter();
private WifiP2pManager.Channel mChannel;
private WifiP2pManager mManager;
private WDBroadcastReceiver receiver;
private ArrayList<WifiP2pDevice> peers = new ArrayList<>();
private final HashMap<String, Map> buddies = new HashMap<String, Map>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: ");
setContentView(R.layout.activity_wd_main);
setupBroadcastReceiver();
setupP2PManager();
mManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "Successfully removed existing group");
initConnection();
}
@Override
public void onFailure(int i) {
Log.i(TAG, "Failed to remove group. It is possible that none exists");
initConnection();
}
});
}
/**
* register the BroadcastReceiver with the intent values to be matched
*/
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
registerWDBroadcastReceiver();
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
@Override
public void onDestroy() {
cleanup();
super.onDestroy();
}
private void setupBroadcastReceiver() {
// Indicates a change in the Wi-Fi P2P status.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
// Indicates a change in the list of available peers.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
// Indicates the state of Wi-Fi P2P connectivity has changed.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
// Indicates this device's details have changed.
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
}
private void registerWDBroadcastReceiver() {
receiver = new WDBroadcastReceiver();
receiver.activity = this;
receiver.mChannel = mChannel;
receiver.mManager = mManager;
registerReceiver(receiver, intentFilter);
discoverService();
}
private void setupP2PManager() {
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), new WifiP2pManager.ChannelListener() {
@Override
public void onChannelDisconnected() {
Log.i(TAG, "Channel disconnected");
}
});
}
private void connect(WifiP2pDevice device) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Toast.makeText(WDMainActivity.this, "Peer connection initiated. Please wait...", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int arg0) {
Log.i(TAG, "Failed to initiate peer connection");
handleActionListenerFailure(arg0);
}
});
}
private void startLocalService() {
if (isServer) {
return;
}
/*
* We are generating the buddy name by appending a random number instead of the device name to keep the buddy name unique at most.
* Because buddy name represents a Wifi direct service to which one could connect to. One device can have more than one such service.
* */
String buddyName = "APP_NAME" + String.valueOf((int)(Math.random()*1000));
// You may display the buddy name in your app so you will know what service to select from the second device
// Create a string map containing information about your service.
Map record = new HashMap();
record.put(KEY_BUDDY_NAME, buddyName);
record.put(KEY_APP_ID, CommunicationProtocol.APP_ID);
// Service information. Pass it an instance name, service type
// _protocol._transportlayer , and the map containing
// information other devices will want once they connect to this one.
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance("_appname", "_presence._tcp", record);
mManager.addLocalService(mChannel, serviceInfo, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "Local service added");
}
@Override
public void onFailure(int arg0) {
Log.i(TAG, "Could not add local service");
}
});
}
private void discoverService() {
WifiP2pManager.DnsSdTxtRecordListener txtListener = new WifiP2pManager.DnsSdTxtRecordListener() {
@Override
/* Callback includes:
* fullDomain: full domain name: e.g "printer._ipp._tcp.local."
* record: TXT record dta as a map of key/value pairs.
* device: The device running the advertised service.
*/
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
if (record.containsKey(KEY_BUDDY_NAME)) {
buddies.put(device.deviceAddress, record);
}
}
};
WifiP2pManager.DnsSdServiceResponseListener servListener = new WifiP2pManager.DnsSdServiceResponseListener() {
@Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType,
WifiP2pDevice resourceType) {
if (buddies
.containsKey(resourceType.deviceAddress) && !peers.contains(resourceType)) {
Map record = buddies.get(resourceType.deviceAddress);
resourceType.deviceName = record.get(KEY_BUDDY_NAME).toString();
peers.add(resourceType);
// You may show the peers in your UI so you could select to pair
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
}
};
mManager.setDnsSdResponseListeners(mChannel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(mChannel,
serviceRequest,
new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "Service request added successfully");
}
@Override
public void onFailure(int code) {
Log.i(TAG, "Failed to add service request");
}
});
mManager.discoverServices(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "Started discovering services");
}
@Override
public void onFailure(int code) {
Log.i(TAG, "Failed to start discovering services");
handleActionListenerFailure(code);
}
});
}
private void initConnection() {
// Service registration and listening
startLocalService();
discoverService();
}
private void cleanup() {
mManager.clearLocalServices(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "Local services cleared");
}
@Override
public void onFailure(int arg0) {
Log.i(TAG, "Could not clear local services");
}
});
mManager.clearServiceRequests(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "Service requestes cleared");
}
@Override
public void onFailure(int arg0) {
Log.i(TAG, "Could not clear service requests");
}
});
}
private void handleActionListenerFailure(int code) {
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn't supported on this device.");
} else if (code == WifiP2pManager.BUSY) {
Log.d(TAG, "The system is to busy to process the request.");
} else if (code == WifiP2pManager.ERROR) {
Log.d(TAG, "The system is to busy to process the request.");
}
}
private void shouldStartServer() {
Log.i(TAG, "shouldStartServer");
// You are the group owner. You should start a TCP server so your peers could connect and exchange IP addresses
}
private void shouldConnectToServer(String ip) {
Log.i(TAG, "shouldConnectToServer: " + ip);
// You are not the group owner. You should connect to the TCP server running in group owner to exchange the IP addresses
}
public void setIsWifiP2pEnabled(Boolean enabled) {
if (!enabled) {
Toast.makeText(this, "Looks like Wifi is disabled or this device does not support Wifi direct.", Toast.LENGTH_LONG).show();
finish();
}
}
//region WifiP2pManager.ConnectionInfoListener
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
Log.i(TAG, "onConnectionInfoAvailable");
if (!info.groupFormed) {
return;
}
Toast.makeText(this, "Group formed", Toast.LENGTH_SHORT).show();
if (info.isGroupOwner) {
shouldStartServer();
} else {
shouldConnectToServer(info.groupOwnerAddress.getHostAddress());
}
}
//endregion
}
public class WDBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "WDBroadcastReceiver";
public WDMainActivity activity;
public WifiP2pManager.Channel mChannel;
public WifiP2pManager mManager;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// Determine if Wifi P2P mode is enabled or not, alert
// the Activity.
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
activity.setIsWifiP2pEnabled(true);
} else {
activity.setIsWifiP2pEnabled(false);
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// Request available peers from the wifi p2p manager. This is an
// asynchronous call and the calling activity is notified with a
// callback on PeerListListener.onPeersAvailable()
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// Connection state changed! We should probably do something about
// that.
if (mManager == null) {
return;
}
NetworkInfo networkInfo = (NetworkInfo) intent
.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
// We are connected with the other device, request connection
// info to find group owner IP
mManager.requestConnectionInfo(mChannel, activity);
}
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment