Initiate a connection
When nearby devices are found, the discoverer can initiate connections. The following example requests a connection with a device as soon as it is discovered.
private final EndpointDiscoveryCallback endpointDiscoveryCallback = new EndpointDiscoveryCallback() { @Override public void onEndpointFound(String endpointId, DiscoveredEndpointInfo info) { // An endpoint was found. We request a connection to it. Nearby.getConnectionsClient(context) .requestConnection(getLocalUserName(), endpointId, connectionLifecycleCallback) .addOnSuccessListener( (Void unused) -> { // We successfully requested a connection. Now both sides // must accept before the connection is established. }) .addOnFailureListener( (Exception e) -> { // Nearby Connections failed to request the connection. }); } @Override public void onEndpointLost(String endpointId) { // A previously discovered endpoint has gone away. } };
Depending on your use case, you may wish to instead display a list of discovered devices to the user, allowing them to choose which devices to connect to.
Accept or reject a connection
After the discoverer has requested a connection to an advertiser, both sides are
notified of the connection initiation process via the onConnectionInitiated()
method of the
ConnectionLifecycleCallback
callback. Note that this callback is passed in to startAdvertising()
on the
advertiser and requestConnection()
on the discoverer, but from this point
forward, the API is symmetric.
Now both sides must choose whether to accept or reject the connection via a call
to acceptConnection()
or rejectConnection()
, respectively. The connection is
fully established only when both sides have accepted. If one or both reject, the
connection is discarded. Either way, the result is delivered to
onConnectionResult()
.
The following code snippet shows how to implement this callback:
private final ConnectionLifecycleCallback connectionLifecycleCallback = new ConnectionLifecycleCallback() { @Override public void onConnectionInitiated(String endpointId, ConnectionInfo connectionInfo) { // Automatically accept the connection on both sides. Nearby.getConnectionsClient(context).acceptConnection(endpointId, payloadCallback); } @Override public void onConnectionResult(String endpointId, ConnectionResolution result) { switch (result.getStatus().getStatusCode()) { case ConnectionsStatusCodes.STATUS_OK: // We're connected! Can now start sending and receiving data. break; case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED: // The connection was rejected by one or both sides. break; case ConnectionsStatusCodes.STATUS_ERROR: // The connection broke before it was able to be accepted. break; default: // Unknown status code } } @Override public void onDisconnected(String endpointId) { // We've been disconnected from this endpoint. No more data can be // sent or received. } };
Again, this example shows the connection being automatically accepted by both sides, but depending on your use case you may wish to present this choice to the user in some way.
Authenticate a connection
When a connection is requested, your app can authenticate the connection by
using the authentication token provided to onConnectionInitiated()
. This
provides a way to let users confirm that they are connecting to the intended
device. Both devices are given the same token, which is a short random string;
it's up to you to decide how to verify it. Typically this involves showing the
token on both devices and asking the users to manually compare and confirm,
similar to a bluetooth pairing dialog.
This sample code demonstrates one way to authenticate by displaying the
authentication token to the user in an AlertDialog
:
@Override public void onConnectionInitiated(String endpointId, ConnectionInfo info) { new AlertDialog.Builder(context) .setTitle("Accept connection to " + info.getEndpointName()) .setMessage("Confirm the code matches on both devices: " + info.getAuthenticationDigits()) .setPositiveButton( "Accept", (DialogInterface dialog, int which) -> // The user confirmed, so we can accept the connection. Nearby.getConnectionsClient(context) .acceptConnection(endpointId, payloadCallback)) .setNegativeButton( android.R.string.cancel, (DialogInterface dialog, int which) -> // The user canceled, so we should reject the connection. Nearby.getConnectionsClient(context).rejectConnection(endpointId)) .setIcon(android.R.drawable.ic_dialog_alert) .show(); }