I try to implement a small test application for Googles Nearby Connections API. Unfortunately on 2 of 3 tested devices Google Play Services chrash when discovering or advertising. (OnePlus One, Android 6.1; Acer Iconia, Android 4.4)
I see other devices, but when i connect to one of them play service crash (only my Honor 8 keeps on working). It says the connection is suspendend with error code 1. According to Google this means "A suspension cause informing that the service has been killed."
Maybe some of you could help. I made this code based on this tutorial. Code without imports:
MainActivity.java
package com.example.steffen.nearbyconnectionsdemo;
public class MainActivity extends Activity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener,
Connections.ConnectionRequestListener,
Connections.MessageListener,
Connections.EndpointDiscoveryListener {
// Identify if the device is the host
private boolean mIsHost = false;
GoogleApiClient mGoogleApiClient = null;
Button bt_ad, bt_search, bt_send;
TextView tv_status;
CheckBox checkBox;
Context c;
String globalRemoteEndpointId = "";
EditText editText;
final int MY_PERMISSIONS_REQUEST = 666;
private static int[] NETWORK_TYPES = {ConnectivityManager.TYPE_WIFI,
ConnectivityManager.TYPE_ETHERNET};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
c = this;
checkPermisson();
editText = (EditText) findViewById(R.id.editText);
bt_ad = (Button) findViewById(R.id.bt_ad);
bt_ad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bt_search.setEnabled(false);
startAdvertising();
}
});
bt_search = (Button) findViewById(R.id.bt_search);
bt_search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startDiscovery();
}
});
bt_send = (Button) findViewById(R.id.bt_send);
bt_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String message = "message: " + editText.getText().toString();
Toast.makeText(c, "Sending: " + message, Toast.LENGTH_SHORT).show();
byte[] payload = message.getBytes();
Nearby.Connections.sendReliableMessage(mGoogleApiClient, globalRemoteEndpointId, payload);
}
});
tv_status = (TextView) findViewById(R.id.tv_status);
checkBox = (CheckBox) findViewById(R.id.checkBox);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Nearby.CONNECTIONS_API)
.build();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
private boolean isConnectedToNetwork() {
ConnectivityManager connManager =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
for (int networkType : NETWORK_TYPES) {
NetworkInfo info = connManager.getNetworkInfo(networkType);
if (info != null && info.isConnectedOrConnecting()) {
return true;
}
}
return false;
}
private void startAdvertising() {
if (!isConnectedToNetwork()) {
// Implement logic when device is not connected to a network
tv_status.setText("No Network");
return;
}
// Identify that this device is the host
mIsHost = true;
checkBox.setChecked(mIsHost);
// Advertising with an AppIdentifer lets other devices on the
// network discover this application and prompt the user to
// install the application.
List<AppIdentifier> appIdentifierList = new ArrayList<>();
appIdentifierList.add(new AppIdentifier(getPackageName()));
AppMetadata appMetadata = new AppMetadata(appIdentifierList);
// The advertising timeout is set to run indefinitely
// Positive values represent timeout in milliseconds
long NO_TIMEOUT = 0L;
String name = null;
Nearby.Connections.startAdvertising(mGoogleApiClient, name, appMetadata, NO_TIMEOUT,
this).setResultCallback(new ResultCallback<Connections.StartAdvertisingResult>() {
@Override
public void onResult(Connections.StartAdvertisingResult result) {
if (result.getStatus().isSuccess()) {
// Device is advertising
tv_status.setText("Advertising");
} else {
int statusCode = result.getStatus().getStatusCode();
// Advertising failed - see statusCode for more details
tv_status.setText("Error: " + statusCode);
}
}
});
}
private void startDiscovery() {
if (!isConnectedToNetwork()) {
// Implement logic when device is not connected to a network
tv_status.setText("No Network");
return;
}
String serviceId = getString(R.string.service_id);
// Set an appropriate timeout length in milliseconds
long DISCOVER_TIMEOUT = 1000L;
// Discover nearby apps that are advertising with the required service ID.
Nearby.Connections.startDiscovery(mGoogleApiClient, serviceId, DISCOVER_TIMEOUT, this)
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
// Device is discovering
tv_status.setText("Discovering");
} else {
int statusCode = status.getStatusCode();
// Advertising failed - see statusCode for more details
tv_status.setText("Error: " + statusCode);
}
}
});
}
@Override
public void onEndpointFound(final String endpointId, String deviceId,
String serviceId, final String endpointName) {
// This device is discovering endpoints and has located an advertiser.
// Write your logic to initiate a connection with the device at
// the endpoint ID
Toast.makeText(this, "Found Device: " + serviceId + ", " + endpointName + ". Start Connection Try", Toast.LENGTH_SHORT).show();
connectTo(endpointId, endpointName);
}
private void connectTo(String remoteEndpointId, final String endpointName) {
// Send a connection request to a remote endpoint. By passing 'null' for
// the name, the Nearby Connections API will construct a default name
// based on device model such as 'LGE Nexus 5'.
tv_status.setText("Connecting");
String myName = null;
byte[] myPayload = null;
Nearby.Connections.sendConnectionRequest(mGoogleApiClient, myName,
remoteEndpointId, myPayload, new Connections.ConnectionResponseCallback() {
@Override
public void onConnectionResponse(String remoteEndpointId, Status status,
byte[] bytes) {
if (status.isSuccess()) {
// Successful connection
tv_status.setText("Connected to " + endpointName);
globalRemoteEndpointId = remoteEndpointId;
} else {
// Failed connection
tv_status.setText("Connecting failed");
}
}
}, this);
}
@Override
public void onConnectionRequest(final String remoteEndpointId, String remoteDeviceId,
final String remoteEndpointName, byte[] payload) {
if (mIsHost) {
byte[] myPayload = null;
// Automatically accept all requests
Nearby.Connections.acceptConnectionRequest(mGoogleApiClient, remoteEndpointId,
myPayload, this).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if (status.isSuccess()) {
String statusS = "Connected to " + remoteEndpointName;
Toast.makeText(c, statusS,
Toast.LENGTH_SHORT).show();
tv_status.setText(statusS);
globalRemoteEndpointId = remoteEndpointId;
} else {
String statusS = "Failed to connect to: " + remoteEndpointName;
Toast.makeText(c, statusS,
Toast.LENGTH_SHORT).show();
tv_status.setText(statusS);
}
}
});
} else {
// Clients should not be advertising and will reject all connection requests.
Nearby.Connections.rejectConnectionRequest(mGoogleApiClient, remoteEndpointId);
}
}
@Override
public void onMessageReceived(String endpointId, byte[] payload, boolean b) {
String message = payload.toString();
Toast.makeText(this, "Received from " + endpointId + ": " + message, Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View view) {
}
@Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override
public void onStop() {
super.onStop();
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
@Override
public void onConnected(Bundle bundle) {
}
@Override
public void onConnectionSuspended(int i) {
tv_status.setText("Connection suspended because of " + i);
mGoogleApiClient.reconnect();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
tv_status.setText("Connection Failed");
}
@Override
public void onEndpointLost(String s) {
tv_status.setText("Endpoint lost: " + s);
}
@Override
public void onDisconnected(String s) {
tv_status.setText("Disconnected: " + s);
}
public void checkPermisson(){
Toast.makeText(c, "Check permission", Toast.LENGTH_SHORT).show();
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_NETWORK_STATE}, MY_PERMISSIONS_REQUEST);
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
Toast.makeText(c, "Permission granted", Toast.LENGTH_SHORT).show();
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(c, "Permission not granted, app may fail", Toast.LENGTH_SHORT).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}