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);
}
}
}
Related
onDestroy() is called when press home button in video call using agora.io .
I have 2 project one is for user and other for astrologer. In User app everything in working fine but in astrologer app onDestroy is calling whenever I press the home button.
This is refernce for agora
https://github.com/AgoraIO/Basic-Video-Call/tree/master/One-to-One-Video/Agora-Android-Tutorial-1to1
public class VideoChatViewActivity extends AppCompatActivity {
private static final String TAG = VideoChatViewActivity.class.getSimpleName();
private static final int PERMISSION_REQ_ID = 22;
// Permission WRITE_EXTERNAL_STORAGE is not mandatory
// for Agora RTC SDK, just in case if you wanna save
// logs to external sdcard.
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private RtcEngine mRtcEngine;
private boolean mCallEnd;
private boolean mMuted;
private FrameLayout mLocalContainer;
private RelativeLayout mRemoteContainer;
private SurfaceView mLocalView;
private SurfaceView mRemoteView;
private ImageView mCallBtn;
private ImageView mMuteBtn;
private ImageView mSwitchCameraBtn;
// Customized logger view
/**
* Event handler registered into RTC engine for RTC callbacks.
* Note that UI operations needs to be in UI thread because RTC
* engine deals with the events in a separate thread.
*/
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
#Override
public void onJoinChannelSuccess(String channel, final int uid, int elapsed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("TAG", "Join channel success, uid: " + (uid & 0xFFFFFFFFL));
}
});
}
#Override
public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("TAG", "First remote video decoded, uid: " + (uid & 0xFFFFFFFFL));
setupRemoteVideo(uid);
}
});
}
#Override
public void onUserOffline(final int uid, int reason) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("TAG", "User offline, uid: " + (uid & 0xFFFFFFFFL));
onRemoteUserLeft();
}
});
}
};
private void setupRemoteVideo(int uid) {
// Only one remote video view is available for this
// tutorial. Here we check if there exists a surface
// view tagged as this uid.
int count = mRemoteContainer.getChildCount();
View view = null;
for (int i = 0; i < count; i++) {
View v = mRemoteContainer.getChildAt(i);
if (v.getTag() instanceof Integer && ((int) v.getTag()) == uid) {
view = v;
}
}
if (view != null) {
return;
}
mRemoteView = RtcEngine.CreateRendererView(getBaseContext());
mRemoteContainer.addView(mRemoteView);
mRtcEngine.setupRemoteVideo(new VideoCanvas(mRemoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
mRemoteView.setTag(uid);
}
private void onRemoteUserLeft() {
removeRemoteVideo();
}
private void removeRemoteVideo() {
if (mRemoteView != null) {
mRemoteContainer.removeView(mRemoteView);
}
mRemoteView = null;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_chat_view);
initUI();
// Ask for permissions at runtime.
// This is just an example set of permissions. Other permissions
// may be needed, and please refer to our online documents.
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID) &&
checkSelfPermission(REQUESTED_PERMISSIONS[2], PERMISSION_REQ_ID)) {
initEngineAndJoinChannel();
}
}
private void initUI() {
mLocalContainer = findViewById(R.id.local_video_view_container);
mRemoteContainer = findViewById(R.id.remote_video_view_container);
mCallBtn = findViewById(R.id.btn_call);
mMuteBtn = findViewById(R.id.btn_mute);
mSwitchCameraBtn = findViewById(R.id.btn_switch_camera);
// Sample logs are optional.
showSampleLogs();
}
private void showSampleLogs() {
Log.e("TAG", "Welcome to Agora 1v1 video call");
}
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) !=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_ID) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED) {
showLongToast("Need permissions " + Manifest.permission.RECORD_AUDIO +
"/" + Manifest.permission.CAMERA + "/" + Manifest.permission.WRITE_EXTERNAL_STORAGE);
finish();
return;
}
// Here we continue only if all permissions are granted.
// The permissions can also be granted in the system settings manually.
initEngineAndJoinChannel();
}
}
private void showLongToast(final String msg) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
private void initEngineAndJoinChannel() {
// This is our usual steps for joining
// a channel and starting a call.
initializeEngine();
setupVideoConfig();
setupLocalVideo();
joinChannel();
}
private void initializeEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e));
}
}
private void setupVideoConfig() {
// In simple use cases, we only need to enable video capturing
// and rendering once at the initialization step.
// Note: audio recording and playing is enabled by default.
mRtcEngine.enableVideo();
// Please go to this page for detailed explanation
// https://docs.agora.io/en/Video/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_rtc_engine.html#af5f4de754e2c1f493096641c5c5c1d8f
mRtcEngine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VideoEncoderConfiguration.VD_640x360,
VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT));
}
private void setupLocalVideo() {
// This is used to set a local preview.
// The steps setting local and remote view are very similar.
// But note that if the local user do not have a uid or do
// not care what the uid is, he can set his uid as ZERO.
// Our server will assign one and return the uid via the event
// handler callback function (onJoinChannelSuccess) after
// joining the channel successfully.
mLocalView = RtcEngine.CreateRendererView(getBaseContext());
mLocalView.setZOrderMediaOverlay(true);
mLocalContainer.addView(mLocalView);
mRtcEngine.setupLocalVideo(new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
}
private void joinChannel() {
// 1. Users can only see each other after they join the
// same channel successfully using the same app id.
// 2. One token is only valid for the channel name that
// you use to generate this token.
mRtcEngine.joinChannel(null, getIntent().getExtras().getString("channel_name"), "Extra Optional Data", 0);
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: ");
if (!mCallEnd) {
leaveChannel();
}
RtcEngine.destroy();
}
#Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause: ");
}
#Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop: ");
}
private void leaveChannel() {
mRtcEngine.leaveChannel();
}
public void onLocalAudioMuteClicked(View view) {
mMuted = !mMuted;
mRtcEngine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_mute;
mMuteBtn.setImageResource(res);
}
public void onSwitchCameraClicked(View view) {
mRtcEngine.switchCamera();
}
public void onCallClicked(View view) {
if (mCallEnd) {
startCall();
mCallEnd = false;
mCallBtn.setImageResource(R.drawable.btn_end_call);
} else {
endCall();
mCallEnd = true;
mCallBtn.setImageResource(R.drawable.btn_end_call);
}
showButtons(!mCallEnd);
}
private void startCall() {
setupLocalVideo();
joinChannel();
}
private void endCall() {
removeLocalVideo();
removeRemoteVideo();
leaveChannel();
}
private void removeLocalVideo() {
if (mLocalView != null) {
mLocalContainer.removeView(mLocalView);
}
mLocalView = null;
}
private void showButtons(boolean show) {
int visibility = show ? View.VISIBLE : View.GONE;
mMuteBtn.setVisibility(visibility);
mSwitchCameraBtn.setVisibility(visibility);
}
}
Welcome to codding party.
you should implement
onSaveInstanceState
and
onRestoreInstanceState
properly. The framework may kill your Activity at any time it isn't foreground.
other way u can Use Foreground service for keeping alive your call.
I'm new in android develop and I'm developing an app that transmit/receive data to a BLE module via Uart service.
With smartphone android 5.x.x the app works fine, it connects with the hardware and receive/transmit data.
With smartphone android 7.x.x the app doesn't connects.
Below you can see a snippet of MainActivity.java:
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_CONNECT_MSG");
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}
}
});
}
It's seem that when SendData, the GATT operation is not yet finished. Smartphone show the message "Device doesn't support UART over BLE. Disconnecting..." due to action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART).
If I delete the if(isConnected)...else... statement also smartphone with android 7.x.x will connects.
My question is what's happen and how can I resolve this issue?
My goal is to send a command to hardware via BLE so when the mcu is connected, a buzzer make a sound.
Thanks for help….
EDIT
Below you can find the whole MainActivity:
public class MainActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
public static final String TAG = "DEBUG ";
public static final String DEV_NAME_FILTER = "";
private static final int REQUEST_SELECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int UART_PROFILE_READY = 10;
private static final int UART_PROFILE_CONNECTED = 20;
public static final int UART_PROFILE_DISCONNECTED = 21;
private static final int STATE_OFF = 10;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
TextView mRemoteRssiVal;
RadioGroup mRg;
private int mState = UART_PROFILE_DISCONNECTED;
private static UartService mService = null;
private static BluetoothDevice mDevice = null;
private BluetoothAdapter mBtAdapter = null;
private ListView messageListView;
private ArrayAdapter<String> listAdapter;
private Button SelectButton, DisconnectButton;
private EditText edtMessage;
private static Context context;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
private static TextView DeviceInfo;
private static TextView DeviceName;
private static TextView Manufacturer;
public static boolean isConnected;
public static boolean isSetting;
public static boolean isReading;
public static boolean isManual;
public static boolean isFunctional;
public static boolean isBootloader;
public static byte[] SettingValues;
public static byte[] ReadingValues;
public static byte[] ManualValues;
public static byte[] FunctionalValues;
private static byte[] Connectcmd = new byte[5];
public static int STX = 0x3E; // '>'
public static int ETX = 0x23; // '#'
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DeviceInfo = (TextView) findViewById(R.id.deviceInfo);
DeviceName = (TextView) findViewById(R.id.deviceName);
Manufacturer= (TextView) findViewById(R.id.manufacturer);
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
context = this;
//Enable location
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M Permission check
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBtAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
SelectButton = (Button) findViewById(R.id.button);
DisconnectButton = (Button) findViewById(R.id.disconnect);
DisconnectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x44; // 'D';
Connectcmd[3] = (byte) 0x43; // 'C'
Connectcmd[4] = (byte) ETX;
try {
//send data to Banner service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
MainActivity.disconnected();
setContentView(R.layout.activity_main);
finish();
} catch (Exception e) {
Log.e(TAG, "Disconnect error");
}
}
});
// Handle Select device button
SelectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onClick - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
if (SelectButton.getText().equals("SELECT CELU")) {
//Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices
Log.i(TAG, "Push button CONNECT");
Intent newIntent = new Intent(context, DeviceListActivity.class);
((Activity) context).startActivityForResult(newIntent, MainActivity.REQUEST_SELECT_DEVICE);
} else {
//Disconnect button pressed
disconnected();
}
}
}
});
// Set initial UI state
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
//UART service connected/disconnected
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder rawBinder) {
mService = ((UartService.LocalBinder) rawBinder).getService();
Log.d(TAG, "onServiceConnected mService= " + mService);
if (!mService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
}
public void onServiceDisconnected(ComponentName classname) {
//// mService.disconnect(mDevice);
mService = null;
}
};
private Handler mHandler = new Handler() {
#Override
//Handler events that received from UART service
public void handleMessage(Message msg) {
}
};
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
Log.d(TAG, "CELU_CONNECT_MSG");
//btnConnectDisconnect.setText("Disconnect");
//edtMessage.setEnabled(true);
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
//IF COMMENTED THE APP CONNECTS!!!!!!!!!!!!!!!!!!
//ELSE IF NOT COMMENTED THE APP NEVER CONNECTS
/*if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}*/
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
});
}
//*********************//
if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_DISCONNECT_MSG");
DisconnectButton.setEnabled(false);
DeviceName.setText("Not Connected");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
//setUiState();
}
});
}
//Enable notifivcation on UART service//
if (action.equals(UartService.ACTION_GATT_SERVICES_DISCOVERED)) {
mService.enableTXNotification();
}
//*********************//
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
try {
ParsingPacket(txValue);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
//*********************//
if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART)) {
showMessage("Device doesn't support UART over BLE Celu . Disconnecting");
mService.disconnect();
}
}
};
private static void ParsingPacket(byte[] packet) throws Exception {
if (packet.length == 0) {
// received empty packet
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
}
if(isSetting){
isSetting = false;
SettingValues = packet.clone();
String text = new String(SettingValues, "UTF-8");
Log.d(TAG, text);
}
if(isReading){
ReadingValues= packet;
ReadActivity.updateMeasure(ReadingValues);
//ReadActivity.addData(packet);
//String text = new String(ReadingValues, "UTF-8");
Log.d("Length ", String.format("%02d", (int) ReadingValues.length));
for(int i=0; i<ReadingValues.length; i++) {
String text = String.format("%02x", (int) ReadingValues[i]);
Log.d(TAG, text);
}
}
if(isManual){
isManual = false;
ManualValues = packet.clone();
String text = new String(ManualValues, "UTF-8");
Log.d(TAG, text);
}
if(isFunctional){
isFunctional = false;
FunctionalValues = packet.clone();
String text = new String(FunctionalValues, "UTF-8");
Log.d(TAG, text);
}
if(isBootloader){
isBootloader = false;
// do samething
}
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
if(DeviceName.getText()!="Not Connected") {
Intent connectedIntent = new Intent(getApplicationContext(), MenuActivity.class); //new Intent("com.antertech.mybleapplication.MenuActivity");
startActivity(connectedIntent);
}
}
};
private void service_init() {
Intent bindIntent = new Intent(this, UartService.class);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UartService.ACTION_GATT_CONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(UartService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART);
return intentFilter;
}
#Override
public void onStart() {
super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
unbindService(mServiceConnection);
mService.stopSelf();
mService = null;
}
#Override
protected void onStop() {
Log.d(TAG, "onStop");
super.onStop();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.end(client, getIndexApiAction());
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.disconnect();
}
#Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
#Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onResume - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_SELECT_DEVICE:
//When the DeviceListActivity return, with the selected device address
if (resultCode == Activity.RESULT_OK && data != null) {
String deviceAddress = data.getStringExtra(BluetoothDevice.EXTRA_DEVICE);
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
Log.d(TAG, "... onActivityResultdevice.address==" + mDevice + " mserviceValue " + mService);
mService.connect(deviceAddress);
//setContentView(R.layout.activity_setting);
((TextView) findViewById(R.id.deviceName)).setText(mDevice.getName() + " - Connecting...");
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Bluetooth has turned on ", Toast.LENGTH_SHORT).show();
} else {
// User did not enable Bluetooth or an error occurred
Log.d(TAG, "BT not enabled");
Toast.makeText(this, "Problem in BT Turning ON ", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
Log.e(TAG, "wrong request code");
break;
}
}
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
}
public static void SendData(byte[] text) {
mService.writeRXCharacteristic(text);
Log.i(TAG, "Message send to Target");
}
public static void disconnected() {
if (mDevice != null) {
mService.disconnect();
Log.i(TAG, "Push Button DISCONNECT");
}
}
private void showMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onBackPressed() {
if (mState == UART_PROFILE_CONNECTED) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
showMessage("CELU TPE running in background.\n Disconnect to exit");
} else {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.popup_title)
.setMessage(R.string.popup_message)
.setPositiveButton(R.string.popup_yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton(R.string.popup_no, null)
.show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[],
int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("Main Page") // TODO: Define a title for the content shown.
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();
return new Action.Builder(Action.TYPE_VIEW)
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
}
I am creating a game using the API of Google Play Games. I have read the documentation on the leaderboards. I have used the same code to update the user's score, but it always returns the code RESULT_RECONNECT_REQUIRED. I've used the logcat to display the results of the call:
E/GameProgress: Result score CgkIoY-5lt0DEAIQEA: ScoreSubmissionData{PlayerId=128090785697, StatusCode=2, TimesSpan=DAILY, Result=null, TimesSpan=WEEKLY, Result=null, TimesSpan=ALL_TIME, Result=null}
Here is the code:
public class GameActivity extends AppCompatActivity {
private GameHelper mHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
...
mHelper = new GameHelper(this, 1);
mHelper.enableDebugLog(true);
mHelper.setup(new GameHelper.GameHelperListener() {
#Override
public void onSignInFailed() {
Log.e(TAG, "Sign in failed");
}
#Override
public void onSignInSucceeded() {
Log.e(TAG, "Sign in Succeded");
addScores(GameId.LEADERBOARDS.TEN_THOUSAND);
}
});
}
private void addScores(String leaderBoard) {
PendingResult<Leaderboards.SubmitScoreResult> result = Games.Leaderboards.submitScoreImmediate(mGoogleApiClient, leaderBoard, 5);
result.setResultCallback(new ResultCallback<Leaderboards.SubmitScoreResult>() {
#Override
public void onResult(#NonNull Leaderboards.SubmitScoreResult submitScoreResult) {
Log.e(TAG, "Result score " + leaderBoard + ": " + submitScoreResult.getScoreData().toString());
}
});
}
}
GameHelperClass:
public class GameHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
static final String TAG = "GameHelper";
public interface GameHelperListener {
void onSignInFailed();
void onSignInSucceeded();
}
private boolean mSetupDone = false;
private boolean mConnecting = false;
boolean mExpectingResolution = false;
boolean mSignInCancelled = false;
Activity mActivity = null;
Context mAppContext = null;
public final static int RC_RESOLVE = 9001;
final static int RC_UNUSED = 9002;
GoogleApiClient.Builder mGoogleApiClientBuilder = null;
GamesOptions mGamesApiOptions = GamesOptions.builder().build();
PlusOptions mPlusApiOptions = null;
GoogleApiClient mGoogleApiClient = null;
// Client request flags
public final static int CLIENT_NONE = 0x00;
public final static int CLIENT_GAMES = 0x01;
public final static int CLIENT_PLUS = 0x02;
public final static int CLIENT_SNAPSHOT = 0x08;
public final static int CLIENT_ALL = CLIENT_GAMES | CLIENT_PLUS
| CLIENT_SNAPSHOT;
int mRequestedClients = CLIENT_NONE;
boolean mConnectOnStart = true;
boolean mUserInitiatedSignIn = false;
ConnectionResult mConnectionResult = null;
SignInFailureReason mSignInFailureReason = null;
boolean mShowErrorDialogs = true;
boolean mDebugLog = false;
Handler mHandler;
Invitation mInvitation;
TurnBasedMatch mTurnBasedMatch;
ArrayList<GameRequest> mRequests;
// Listener
GameHelperListener mListener = null;
static final int DEFAULT_MAX_SIGN_IN_ATTEMPTS = 3;
int mMaxAutoSignInAttempts = DEFAULT_MAX_SIGN_IN_ATTEMPTS;
private GameErrorHandler mGameErrorHandler;
public GameHelper(Activity activity, int clientsToUse) {
mActivity = activity;
mAppContext = activity.getApplicationContext();
mRequestedClients = clientsToUse;
mHandler = new Handler();
}
public void setMaxAutoSignInAttempts(int max) {
mMaxAutoSignInAttempts = max;
}
public void setGameErrorHandler(GameErrorHandler mGameErrorHandler) {
this.mGameErrorHandler = mGameErrorHandler;
}
void assertConfigured(String operation) {
if (!mSetupDone) {
String error = "GameHelper error: Operation attempted without setup: "
+ operation
+ ". The setup() method must be called before attempting any other operation.";
logError(error);
throw new IllegalStateException(error);
}
}
private void doApiOptionsPreCheck() {
if (mGoogleApiClientBuilder != null) {
String error = "GameHelper: you cannot call set*ApiOptions after the client "
+ "builder has been created. Call it before calling createApiClientBuilder() "
+ "or setup().";
logError(error);
throw new IllegalStateException(error);
}
}
public void setGamesApiOptions(GamesOptions options) {
doApiOptionsPreCheck();
mGamesApiOptions = options;
}
public void setPlusApiOptions(PlusOptions options) {
doApiOptionsPreCheck();
mPlusApiOptions = options;
}
public GoogleApiClient.Builder createApiClientBuilder() {
if (mSetupDone) {
String error = "GameHelper: you called GameHelper.createApiClientBuilder() after "
+ "calling setup. You can only get a client builder BEFORE performing setup.";
logError(error);
throw new IllegalStateException(error);
}
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(
mActivity, this, this);
if (0 != (mRequestedClients & CLIENT_GAMES)) {
builder.addApi(Games.API, mGamesApiOptions);
builder.addScope(Games.SCOPE_GAMES);
}
if (0 != (mRequestedClients & CLIENT_PLUS)) {
builder.addApi(Plus.API);
builder.addScope(Plus.SCOPE_PLUS_LOGIN);
}
if (0 != (mRequestedClients & CLIENT_SNAPSHOT)) {
builder.addScope(Drive.SCOPE_APPFOLDER);
builder.addApi(Drive.API);
}
mGoogleApiClientBuilder = builder;
return builder;
}
public void setup(GameHelperListener listener) {
if (mSetupDone) {
String error = "GameHelper: you cannot call GameHelper.setup() more than once!";
logError(error);
throw new IllegalStateException(error);
}
mListener = listener;
debugLog("Setup: requested clients: " + mRequestedClients);
if (mGoogleApiClientBuilder == null) {
// we don't have a builder yet, so create one
createApiClientBuilder();
}
mGoogleApiClient = mGoogleApiClientBuilder.build();
mGoogleApiClientBuilder = null;
mSetupDone = true;
}
public GoogleApiClient getApiClient() {
if (mGoogleApiClient == null) {
throw new IllegalStateException(
"No GoogleApiClient. Did you call setup()?");
}
return mGoogleApiClient;
}
public boolean isSignedIn() {
return mGoogleApiClient != null && mGoogleApiClient.isConnected();
}
public boolean isConnecting() {
return mConnecting;
}
public boolean hasSignInError() {
return mSignInFailureReason != null;
}
public SignInFailureReason getSignInError() {
return mSignInFailureReason;
}
public void setShowErrorDialogs(boolean show) {
mShowErrorDialogs = show;
}
public void onStart(Activity act) {
mActivity = act;
mAppContext = act.getApplicationContext();
debugLog("onStart");
assertConfigured("onStart");
if (mConnectOnStart) {
if (mGoogleApiClient.isConnected()) {
Log.w(TAG,
"GameHelper: client was already connected on onStart()");
} else {
debugLog("Connecting client.");
mConnecting = true;
mGoogleApiClient.connect();
}
} else {
debugLog("Not attempting to connect becase mConnectOnStart=false");
debugLog("Instead, reporting a sign-in failure.");
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
notifyListener(false);
}
}, 1000);
}
}
public void onStop() {
debugLog("onStop");
assertConfigured("onStop");
if (mGoogleApiClient.isConnected()) {
debugLog("Disconnecting client due to onStop");
mGoogleApiClient.disconnect();
} else {
debugLog("Client already disconnected when we got onStop.");
}
mConnecting = false;
mExpectingResolution = false;
// let go of the Activity reference
mActivity = null;
}
public String getInvitationId() {
if (!mGoogleApiClient.isConnected()) {
Log.w(TAG,
"Warning: getInvitationId() should only be called when signed in, "
+ "that is, after getting onSignInSuceeded()");
}
return mInvitation == null ? null : mInvitation.getInvitationId();
}
public Invitation getInvitation() {
if (!mGoogleApiClient.isConnected()) {
Log.w(TAG,
"Warning: getInvitation() should only be called when signed in, "
+ "that is, after getting onSignInSuceeded()");
}
return mInvitation;
}
public boolean hasInvitation() {
return mInvitation != null;
}
public boolean hasTurnBasedMatch() {
return mTurnBasedMatch != null;
}
public boolean hasRequests() {
return mRequests != null;
}
public void clearInvitation() {
mInvitation = null;
}
public void clearTurnBasedMatch() {
mTurnBasedMatch = null;
}
public void clearRequests() {
mRequests = null;
}
public TurnBasedMatch getTurnBasedMatch() {
if (!mGoogleApiClient.isConnected()) {
Log.w(TAG,
"Warning: getTurnBasedMatch() should only be called when signed in, "
+ "that is, after getting onSignInSuceeded()");
}
return mTurnBasedMatch;
}
public ArrayList<GameRequest> getRequests() {
if (!mGoogleApiClient.isConnected()) {
Log.w(TAG, "Warning: getRequests() should only be called "
+ "when signed in, "
+ "that is, after getting onSignInSuceeded()");
}
return mRequests;
}
public void enableDebugLog(boolean enabled) {
mDebugLog = enabled;
if (enabled) {
debugLog("Debug log enabled.");
}
}
#Deprecated
public void enableDebugLog(boolean enabled, String tag) {
Log.w(TAG, "GameHelper.enableDebugLog(boolean,String) is deprecated. "
+ "Use GameHelper.enableDebugLog(boolean)");
enableDebugLog(enabled);
}
public void signOut() {
if (!mGoogleApiClient.isConnected()) {
// nothing to do
debugLog("signOut: was already disconnected, ignoring.");
return;
}
// for Plus, "signing out" means clearing the default account and
// then disconnecting
if (0 != (mRequestedClients & CLIENT_PLUS)) {
debugLog("Clearing default account on PlusClient.");
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
}
// For the games client, signing out means calling signOut and
// disconnecting
if (0 != (mRequestedClients & CLIENT_GAMES)) {
debugLog("Signing out from the Google API Client.");
Games.signOut(mGoogleApiClient);
}
// Ready to disconnect
debugLog("Disconnecting client.");
mConnectOnStart = false;
mConnecting = false;
mGoogleApiClient.disconnect();
}
public void onActivityResult(int requestCode, int responseCode,
Intent intent) {
debugLog("onActivityResult: req="
+ (requestCode == RC_RESOLVE ? "RC_RESOLVE" : String
.valueOf(requestCode)) + ", resp="
+ GameHelperUtils.activityResponseCodeToString(responseCode));
if (requestCode != RC_RESOLVE) {
debugLog("onActivityResult: request code not meant for us. Ignoring.");
return;
}
// no longer expecting a resolution
mExpectingResolution = false;
/* if (!mConnecting) {
debugLog("onActivityResult: ignoring because we are not connecting.");
return;
}*/
if (responseCode == Activity.RESULT_OK) {
// Ready to try to connect again.
debugLog("onAR: Resolution was RESULT_OK, so connecting current client again.");
connect();
} else if (responseCode == GamesActivityResultCodes.RESULT_RECONNECT_REQUIRED) {
debugLog("onAR: Resolution was RECONNECT_REQUIRED, so reconnecting.");
connect();
fireOnReconectRequired();
} else if (responseCode == Activity.RESULT_CANCELED) {
// User cancelled.
debugLog("onAR: Got a cancellation result, so disconnecting.");
mSignInCancelled = true;
mConnectOnStart = false;
mUserInitiatedSignIn = false;
mSignInFailureReason = null; // cancelling is not a failure!
mConnecting = false;
mGoogleApiClient.disconnect();
// increment # of cancellations
int prevCancellations = getSignInCancellations();
int newCancellations = incrementSignInCancellations();
debugLog("onAR: # of cancellations " + prevCancellations + " --> "
+ newCancellations + ", max " + mMaxAutoSignInAttempts);
notifyListener(false);
} else {
// Whatever the problem we were trying to solve, it was not
// solved. So give up and show an error message.
debugLog("onAR: responseCode="
+ GameHelperUtils
.activityResponseCodeToString(responseCode)
+ ", so giving up.");
giveUp(new SignInFailureReason(mConnectionResult.getErrorCode(),
responseCode));
}
}
void notifyListener(boolean success) {
debugLog("Notifying LISTENER of sign-in "
+ (success ? "SUCCESS"
: mSignInFailureReason != null ? "FAILURE (error)"
: "FAILURE (no error)"));
if (mListener != null) {
if (success) {
mListener.onSignInSucceeded();
} else {
mListener.onSignInFailed();
}
}
}
public void beginUserInitiatedSignIn() {
debugLog("beginUserInitiatedSignIn: resetting attempt count.");
resetSignInCancellations();
mSignInCancelled = false;
mConnectOnStart = true;
if (mGoogleApiClient.isConnected()) {
// nothing to do
logWarn("beginUserInitiatedSignIn() called when already connected. "
+ "Calling listener directly to notify of success.");
notifyListener(true);
return;
} else if (mConnecting) {
logWarn("beginUserInitiatedSignIn() called when already connecting. "
+ "Be patient! You can only call this method after you get an "
+ "onSignInSucceeded() or onSignInFailed() callback. Suggestion: disable "
+ "the sign-in button on startup and also when it's clicked, and re-enable "
+ "when you get the callback.");
// ignore call (listener will get a callback when the connection
// process finishes)
return;
}
debugLog("Starting USER-INITIATED sign-in flow.");
mUserInitiatedSignIn = true;
if (mConnectionResult != null) {
debugLog("beginUserInitiatedSignIn: continuing pending sign-in flow.");
mConnecting = true;
resolveConnectionResult();
} else {
// We don't have a pending connection result, so start anew.
debugLog("beginUserInitiatedSignIn: starting new sign-in flow.");
mConnecting = true;
connect();
}
}
void connect() {
if (mGoogleApiClient.isConnected()) {
debugLog("Already connected.");
return;
}
debugLog("Starting connection.");
mConnecting = true;
mInvitation = null;
mTurnBasedMatch = null;
mGoogleApiClient.connect();
}
public void reconnectClient() {
if (!mGoogleApiClient.isConnected()) {
Log.w(TAG, "reconnectClient() called when client is not connected.");
// interpret it as a request to connect
connect();
} else {
debugLog("Reconnecting client.");
mGoogleApiClient.reconnect();
}
}
#Override
public void onConnected(Bundle connectionHint) {
debugLog("onConnected: connected!");
if (connectionHint != null) {
debugLog("onConnected: connection hint provided. Checking for invite.");
Invitation inv = connectionHint
.getParcelable(Multiplayer.EXTRA_INVITATION);
if (inv != null && inv.getInvitationId() != null) {
// retrieve and cache the invitation ID
debugLog("onConnected: connection hint has a room invite!");
mInvitation = inv;
debugLog("Invitation ID: " + mInvitation.getInvitationId());
}
// Do we have any requests pending?
mRequests = Games.Requests
.getGameRequestsFromBundle(connectionHint);
if (!mRequests.isEmpty()) {
// We have requests in onConnected's connectionHint.
debugLog("onConnected: connection hint has " + mRequests.size()
+ " request(s)");
}
debugLog("onConnected: connection hint provided. Checking for TBMP game.");
mTurnBasedMatch = connectionHint
.getParcelable(Multiplayer.EXTRA_TURN_BASED_MATCH);
}
// we're good to go
succeedSignIn();
}
void succeedSignIn() {
debugLog("succeedSignIn");
mSignInFailureReason = null;
mConnectOnStart = true;
mUserInitiatedSignIn = false;
mConnecting = false;
notifyListener(true);
}
private final String GAMEHELPER_SHARED_PREFS = "GAMEHELPER_SHARED_PREFS";
private final String KEY_SIGN_IN_CANCELLATIONS = "KEY_SIGN_IN_CANCELLATIONS";
// Return the number of times the user has cancelled the sign-in flow in the
// life of the app
int getSignInCancellations() {
SharedPreferences sp = mAppContext.getSharedPreferences(
GAMEHELPER_SHARED_PREFS, Context.MODE_PRIVATE);
return sp.getInt(KEY_SIGN_IN_CANCELLATIONS, 0);
}
int incrementSignInCancellations() {
int cancellations = getSignInCancellations();
SharedPreferences.Editor editor = mAppContext.getSharedPreferences(
GAMEHELPER_SHARED_PREFS, Context.MODE_PRIVATE).edit();
editor.putInt(KEY_SIGN_IN_CANCELLATIONS, cancellations + 1);
editor.commit();
return cancellations + 1;
}
void resetSignInCancellations() {
SharedPreferences.Editor editor = mAppContext.getSharedPreferences(
GAMEHELPER_SHARED_PREFS, Context.MODE_PRIVATE).edit();
editor.putInt(KEY_SIGN_IN_CANCELLATIONS, 0);
editor.commit();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// save connection result for later reference
debugLog("onConnectionFailed");
mConnectionResult = result;
debugLog("Connection failure:");
debugLog(" - code: "
+ GameHelperUtils.errorCodeToString(mConnectionResult
.getErrorCode()));
debugLog(" - resolvable: " + mConnectionResult.hasResolution());
debugLog(" - details: " + mConnectionResult.toString());
int cancellations = getSignInCancellations();
boolean shouldResolve = false;
if (mUserInitiatedSignIn) {
debugLog("onConnectionFailed: WILL resolve because user initiated sign-in.");
shouldResolve = true;
} else if (mSignInCancelled) {
debugLog("onConnectionFailed WILL NOT resolve (user already cancelled once).");
shouldResolve = false;
} else if (cancellations < mMaxAutoSignInAttempts) {
debugLog("onConnectionFailed: WILL resolve because we have below the max# of "
+ "attempts, "
+ cancellations
+ " < "
+ mMaxAutoSignInAttempts);
shouldResolve = true;
} else {
shouldResolve = false;
debugLog("onConnectionFailed: Will NOT resolve; not user-initiated and max attempts "
+ "reached: "
+ cancellations
+ " >= "
+ mMaxAutoSignInAttempts);
}
if (!shouldResolve) {
// Fail and wait for the user to want to sign in.
debugLog("onConnectionFailed: since we won't resolve, failing now.");
mConnectionResult = result;
mConnecting = false;
notifyListener(false);
return;
}
debugLog("onConnectionFailed: resolving problem...");
resolveConnectionResult();
}
void resolveConnectionResult() {
// Try to resolve the problem
if (mExpectingResolution) {
debugLog("We're already expecting the result of a previous resolution.");
return;
}
if (mActivity == null) {
debugLog("No need to resolve issue, activity does not exist anymore");
return;
}
debugLog("resolveConnectionResult: trying to resolve result: "
+ mConnectionResult);
if (mConnectionResult.hasResolution()) {
// This problem can be fixed. So let's try to fix it.
debugLog("Result has resolution. Starting it.");
try {
// launch appropriate UI flow (which might, for example, be the
// sign-in flow)
mExpectingResolution = true;
mConnectionResult.startResolutionForResult(mActivity,
RC_RESOLVE);
} catch (SendIntentException e) {
// Try connecting again
debugLog("SendIntentException, so connecting again.");
connect();
}
} else {
// It's not a problem what we can solve, so give up and show an
// error.
debugLog("resolveConnectionResult: result has no resolution. Giving up.");
giveUp(new SignInFailureReason(mConnectionResult.getErrorCode()));
mConnectionResult = null;
}
}
public void disconnect() {
if (mGoogleApiClient.isConnected()) {
debugLog("Disconnecting client.");
mGoogleApiClient.disconnect();
} else {
Log.w(TAG,
"disconnect() called when client was already disconnected.");
}
}
void giveUp(SignInFailureReason reason) {
mConnectOnStart = false;
disconnect();
mSignInFailureReason = reason;
if (reason.mActivityResultCode == GamesActivityResultCodes.RESULT_APP_MISCONFIGURED) {
// print debug info for the developer
GameHelperUtils.printMisconfiguredDebugInfo(mAppContext);
}
showFailureDialog();
mConnecting = false;
notifyListener(false);
}
#Override
public void onConnectionSuspended(int cause) {
debugLog("onConnectionSuspended, cause=" + cause);
disconnect();
mSignInFailureReason = null;
debugLog("Making extraordinary call to onSignInFailed callback");
mConnecting = false;
notifyListener(false);
}
. . .
void debugLog(String message) {
if (mDebugLog) {
Log.d(TAG, message);
}
}
void logWarn(String message) {
Log.w(TAG, "!!! GameHelper WARNING: " + message);
}
void logError(String message) {
Log.e(TAG, "*** GameHelper ERROR: " + message);
}
// Represents the reason for a sign-in failure
public static class SignInFailureReason {
public static final int NO_ACTIVITY_RESULT_CODE = -100;
int mServiceErrorCode = 0;
int mActivityResultCode = NO_ACTIVITY_RESULT_CODE;
public int getServiceErrorCode() {
return mServiceErrorCode;
}
public int getActivityResultCode() {
return mActivityResultCode;
}
public SignInFailureReason(int serviceErrorCode, int activityResultCode) {
mServiceErrorCode = serviceErrorCode;
mActivityResultCode = activityResultCode;
}
public SignInFailureReason(int serviceErrorCode) {
this(serviceErrorCode, NO_ACTIVITY_RESULT_CODE);
}
public void setConnectOnStart(boolean connectOnStart) {
debugLog("Forcing mConnectOnStart=" + connectOnStart);
mConnectOnStart = connectOnStart;
}
}
I've tried to change the score, but there is nothing, I have also checked that the leaderboard is set up correctly.
I have tried connecting to the Nearby Messages API, and have successfully been able to subscribe.
Now, my mMessageListener field is never getting callbacks for some reason.
I have already configured my beacons using the proximity beacon api using the Android beacon service demo app.
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
// Declaration of member variables
private GoogleApiClient mGoogleApiClient;
private final String TAG = "Bridge.MainActivity";
private boolean mResolvingError = false;
private static final int REQUEST_RESOLVE_ERROR = 100;
private static final int REQUEST_PERMISSION = 42;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initializing the Google API client
}
private MessageListener mMessageListener = new MessageListener() {
#Override
public void onFound(Message message) {
// Do something with the message
Log.i(TAG, " Found Message : " + message.toString());
}
#Override
public void onLost(Message message) {
super.onLost(message);
Log.i(TAG, " Found Message : " + message.toString());
}
};
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG, "GoogleAPi Client Connected");
foregorundSubscribeBeacons();
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "Google Api Connection Suspended : " + i);
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG, "GoogleApi Connection failed : " + connectionResult.getErrorMessage());
}
public void foregorundSubscribeBeacons() {
// Subscribe to receive messages
Log.i(TAG, "Trying to subscribe");
if (!mGoogleApiClient.isConnected()) {
if (!mGoogleApiClient.isConnecting()) {
mGoogleApiClient.connect();
}
} else {
SubscribeOptions options = new SubscribeOptions.Builder()
.setStrategy(Strategy.BLE_ONLY)
.setCallback(new SubscribeCallback() {
#Override
public void onExpired() {
Log.i(TAG, "No longer subscribing.");
}
}).build();
Nearby.Messages.subscribe(mGoogleApiClient, mMessageListener, options)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Subscribed successfully.");
} else {
Log.i(TAG, "Could not subscribe.");
// Check whether consent was given;
// if not, prompt the user for consent.
handleUnsuccessfulNearbyResult(status);
}
}
});
}
}
private void handleUnsuccessfulNearbyResult(Status status) {
Log.i(TAG, "Processing error, status = " + status);
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (status.hasResolution()) {
try {
mResolvingError = true;
status.startResolutionForResult(this,
REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
mResolvingError = false;
Log.i(TAG, "Failed to resolve error status.", e);
}
} else {
if (status.getStatusCode() == CommonStatusCodes.NETWORK_ERROR) {
Toast.makeText(this.getApplicationContext(),
"No connectivity, cannot proceed. Fix in 'Settings' and try again.",
Toast.LENGTH_LONG).show();
} else {
// To keep things simple, pop a toast for all other error messages.
Toast.makeText(this.getApplicationContext(), "Unsuccessful: " +
status.getStatusMessage(), Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_RESOLVE_ERROR) {
// User was presented with the Nearby opt-in dialog and pressed "Allow".
mResolvingError = false;
if (resultCode == RESULT_OK) {
// Execute the pending subscription and publication tasks here.
foregorundSubscribeBeacons();
} else if (resultCode == RESULT_CANCELED) {
// User declined to opt-in. Reset application state here.
} else {
Toast.makeText(this, "Failed to resolve error with code " + resultCode,
Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onStart() {
super.onStart();
//Initiate connection to Play Services
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Nearby.MESSAGES_API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
//The location permission is required on API 23+ to obtain BLE scan results
int result = ActivityCompat
.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (result != PackageManager.PERMISSION_GRANTED) {
//Ask for the location permission
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_PERMISSION);
}
}
#Override
protected void onStop() {
super.onStop();
//Tear down Play Services connection
if (mGoogleApiClient.isConnected()) {
Log.d(TAG, "Un-subscribing…");
mGoogleApiClient.disconnect();
}
}
Make sure both the Beacon Service Demo App and the app using Nearby Messages are part of the same Google Developers Console project. You will only see messages attached by your own project.
If you have successfully done the beacon registration, adding the attachment to beacon on the Google Beacon Registry Server; then on subscribed successfully on device.
PRE-PREPARATION IS NECESSARY, ELSE YOU WON'T GET THE THINGS ON DEVICE.
So when beacon gets detected, the onFound(Message msg) gets called for each attachment of respective beacon.
THEY CLEARLY SAID, "DO SOMETHING WITH MESSAGE" in onFound(), so process your attachment only there, not the outside of onFound().
Here, if you print variable msg into Log, it should look like this :
Message{namespace='yourprojectname-1234', type='abcd', content=[614 bytes], devices=[NearbyDevice{id=NearbyDeviceId{UNKNOWN}}]}
Get the attachment content with msg.getContent() into String variable. This is normal text, and not in the base64 format.
Once you get the string content, DO WHATEVER you wanted to do.
Now it's up to you what content goes into attachment.
I have used JSON in the attachment and successfully processed for my purpose.
I am doing a module where i need to make user login through google plus.
I can get name and email of user but struck with getting list of people in his/her circle.
Does any one know how to get list of people in the person circles.??
Here is my code .Some what lengthy..
public class SignIn extends Activity implements ResultCallback<People.LoadPeopleResult>,ConnectionCallbacks, OnConnectionFailedListener ,OnClickListener
{
//declaration of variables
static final String EMAIL_PATTERN =
"^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*#"
+ "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.signin_layout);
//googleapiclient initialization..
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API, null)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.build();
initializecontrols();
cancel.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
finish();
}
});
login.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0)
{
String em=email.getText().toString();
String ps=pswd.getText().toString();
if(em.length()==0||ps.length()==0)
{
Toast.makeText(getApplicationContext(), "Enter all the above", Toast.LENGTH_SHORT).show();
}
else
{
if(validate(em))
{
Toast.makeText(getApplicationContext(), "Login Sucess", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getApplicationContext(), "Wrong email format", Toast.LENGTH_SHORT).show();
}
}
}
});
fb.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0)
{
Toast.makeText(getApplicationContext(), "yet to do..", Toast.LENGTH_SHORT).show();
}
});
gp.setOnClickListener(this);
}
public boolean validate(final String hex)
{
matcher = pattern.matcher(hex);
return matcher.matches();
}
public void onConnectionFailed(ConnectionResult result) {
if (!mIntentInProgress) {
// Store the ConnectionResult so that we can use it later when the user clicks
// 'sign-in'.
mConnectionResult = result;
if (mSignInClicked) {
// The user has already clicked 'sign-in' so we attempt to resolve all
// errors until the user is signed in, or they cancel.
resolveSignInError();
}
}
}
#Override
public void onClick(View v)
{
if(v.getId()==R.id.gplogin && !mGoogleApiClient.isConnecting())
{
mSignInClicked = true;
mGoogleApiClient.connect();
}
}
protected void onStart() {
super.onStart();
// mGoogleApiClient.connect();
}
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onConnected(Bundle arg0) {
mSignInClicked = false;
Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
getProfileInformation();
Plus.PeopleApi.loadVisible(mGoogleApiClient, null)
.setResultCallback(this);
mGoogleApiClient.disconnect();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
#Override
protected void onActivityResult(int requestCode, int responseCode,
Intent intent) {
if (requestCode == RC_SIGN_IN) {
if (responseCode != RESULT_OK) {
mSignInClicked = false;
}
mIntentInProgress = false;
if (!mGoogleApiClient.isConnecting()) {
mGoogleApiClient.connect();
}
}
}
private void signInWithGplus() {
if (!mGoogleApiClient.isConnecting()) {
mSignInClicked = true;
resolveSignInError();
}
}
private void resolveSignInError() {
if (mConnectionResult.hasResolution()) {
try {
mIntentInProgress = true;
mConnectionResult.startResolutionForResult(this, RC_SIGN_IN);
} catch (SendIntentException e) {
mIntentInProgress = false;
mGoogleApiClient.connect();
}
}
}
private void getProfileInformation() {
try {
if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null)
{
Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
String personName = currentPerson.getDisplayName();
String personPhotoUrl = currentPerson.getImage().getUrl();
String personGooglePlusProfile = currentPerson.getUrl();
String nickname = currentPerson.getNickname();
String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
Log.e("Output :", "Name: " + personName + ", plusProfile: "
+ personGooglePlusProfile + ", email: " + email
+ ", Image: " + personPhotoUrl);
Toast.makeText(getApplicationContext(),"Name : "+personName+"\n Email :"+email, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(),
"Person information is null", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onResult(LoadPeopleResult peopleData)
{
Log.e("function","onResult");
if (peopleData.getStatus().getStatusCode() == CommonStatusCodes.SUCCESS) {
PersonBuffer personBuffer = peopleData.getPersonBuffer();
try {
int count = personBuffer.getCount();
for (int i = 0; i < count; i++) {
Log.d("Person", "Display name: " + personBuffer.get(i).getDisplayName());
}
} finally {
personBuffer.close();
}
} else {
Log.e("person", "Error requesting visible circles: " + peopleData.getStatus());
}
}
}
According to the tutorial onResult callback method will be called when
Plus.PeopleApi.loadVisible(mGoogleApiClient, null)
.setResultCallback(this);
this particular code is executed in OnConnected method
You are disconnecting immediately after you make the request.
Google Play services uses a client-service architecture with asynchronous callbacks. Disconnecting actually closes the service connection, preventing the response from being delivered back to you. This is akin to calling up your buddy, saying "hey, how's it going" and then immediately hanging up your phone.
As an aside, there are a couple other non-standard things going on here. In general you should call connect in onStart() (you have this commented out). If the user has already given your app permission then you can immediately start getting data and doing what you want with it. If the user hasn't granted permission or there's another issue (like it's a Kindle Fire, where Google Play services isn't available), then you'll get onConnectionFailed. You can then hold on to that Status and call the resolution when the user clicks on the button. This will result in a snappier UI and make it easier for you to match your connect() and disconnect() calls.
In general disconnect() should be called in onStop(). This way you won't disconnect until your activity is being torn down anyway.