Last active
January 21, 2019 17:33
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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