I am currently trying to work with Google Fit API.This is my first App using the API, and I have been mainly by following Google's documentation.
Below is the code that I have which seems to have a problem
The problem I have is that it doesn't seem to be updating the step counter.
public class MainActivity extends Activity
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "FitActivity";
//[START Auth_Variable_References]
private static final int REQUEST_OAUTH = 1;
// [END auth_variable_references]
private GoogleApiClient mClient = null;
int mInitialNumberOfSteps = 0;
private TextView mStepsTextView;
private boolean mFirstCount = true;
// Create Builder View
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStepsTextView = (TextView) findViewById(R.id.textview_number_of_steps);
}
private void connectFitness() {
Log.i(TAG, "Connecting...");
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
// select the Fitness API
.addApi(Fitness.API)
// specify the scopes of access
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
// provide callbacks
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
// Connect the Google API client
mClient.connect();
}
// Manage OAuth authentication
#Override
public void onConnectionFailed(ConnectionResult result) {
// Error while connecting. Try to resolve using the pending intent returned.
if (result.getErrorCode() == ConnectionResult.SIGN_IN_REQUIRED ||
result.getErrorCode() == FitnessStatusCodes.NEEDS_OAUTH_PERMISSIONS) {
try {
// Request authentication
result.startResolutionForResult(this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception connecting to the fitness service", e);
}
} else {
Log.e(TAG, "Unknown connection issue. Code = " + result.getErrorCode());
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
if (resultCode == RESULT_OK) {
// If the user authenticated, try to connect again
mClient.connect();
}
}
}
#Override
public void onConnectionSuspended(int i) {
// If your connection gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!");
// Now you can make calls to the Fitness APIs.
invokeFitnessAPIs();
}
private void invokeFitnessAPIs() {
// Create a listener object to be called when new data is available
OnDataPointListener listener = new OnDataPointListener() {
#Override
public void onDataPoint(DataPoint dataPoint) {
for (Field field : dataPoint.getDataType().getFields()) {
Value val = dataPoint.getValue(field);
updateTextViewWithStepCounter(val.asInt());
}
}
};
//Specify what data sources to return
DataSourcesRequest req = new DataSourcesRequest.Builder()
.setDataSourceTypes(DataSource.TYPE_DERIVED)
.setDataTypes(DataType.TYPE_STEP_COUNT_DELTA)
.build();
// Invoke the Sensors API with:
// - The Google API client object
// - The data sources request object
PendingResult<DataSourcesResult> pendingResult =
Fitness.SensorsApi.findDataSources(mClient, req);
// Build a sensor registration request object
SensorRequest sensorRequest = new SensorRequest.Builder()
.setDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
.setSamplingRate(1, TimeUnit.SECONDS)
.build();
// Invoke the Sensors API with:
// - The Google API client object
// - The sensor registration request object
// - The listener object
PendingResult<Status> regResult =
Fitness.SensorsApi.add(mClient,
new SensorRequest.Builder()
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.build(),
listener);
// 4. Check the result asynchronously
regResult.setResultCallback(new ResultCallback<Status>()
{
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.d(TAG, "listener registered");
// listener registered
} else {
Log.d(TAG, "listener not registered");
// listener not registered
}
}
});
}
// Update the Text Viewer with Counter of Steps..
private void updateTextViewWithStepCounter(final int numberOfSteps) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "On Datapoint!", Toast.LENGTH_SHORT);
if(mFirstCount && (numberOfSteps != 0)) {
mInitialNumberOfSteps = numberOfSteps;
mFirstCount = false;
}
if(mStepsTextView != null){
mStepsTextView.setText(String.valueOf(numberOfSteps - mInitialNumberOfSteps));
}
}
});
}
//Start
#Override
protected void onStart() {
super.onStart();
mFirstCount = true;
mInitialNumberOfSteps = 0;
if (mClient == null || !mClient.isConnected()) {
connectFitness();
}
}
//Stop
#Override
protected void onStop() {
super.onStop();
if(mClient.isConnected() || mClient.isConnecting()) mClient.disconnect();
mInitialNumberOfSteps = 0;
mFirstCount = true;
}
}
First of all,
Follow these steps to enable the Fitness API in the Google API Console and get an OAuth 2.0 client ID.
1. Go to the Google API Console.
2. Select a project, or create a new one. Use the same project for the Android and REST versions of your app.
3. Click Continue to enable the Fitness API.
4. Click Go to credentials.
5. Click New credentials, then select OAuth Client ID.
6. Under Application type select Android.
7. In the resulting dialog, enter your app's SHA-1 fingerprint and package name. For example:
BB:0D:AC:74:D3:21:E1:43:67:71:9B:62:91:AF:A1:66:6E:44:5D:75
com.example.android.fit-example
8. Click Create. Your new Android OAuth 2.0 Client ID and secret appear in the list of IDs for your project. An OAuth 2.0 Client ID is a string of characters, something like this:
780816631155-gbvyo1o7r2pn95qc4ei9d61io4uh48hl.apps.googleusercontent.com
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Scope;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.data.DataPoint;
import com.google.android.gms.fitness.data.DataSource;
import com.google.android.gms.fitness.data.DataType;
import com.google.android.gms.fitness.data.Field;
import com.google.android.gms.fitness.data.Value;
import com.google.android.gms.fitness.request.DataSourcesRequest;
import com.google.android.gms.fitness.request.OnDataPointListener;
import com.google.android.gms.fitness.request.SensorRequest;
import com.google.android.gms.fitness.result.DataSourcesResult;
import java.util.concurrent.TimeUnit;
/**
* Created by Admin on Dec/8/2016.
* <p/>
* <p/>
* http://stackoverflow.com/questions/28476809/step-counter-google-fit-api?rq=1
*/
public class StackOverflowActivity extends AppCompatActivity
{
private static final String TAG = "FitActivity";
private GoogleApiClient mClient = null;
private OnDataPointListener mListener;
// Create Builder View
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
connectFitness();
}
private void connectFitness() {
if (mClient == null){
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ)) // GET STEP VALUES
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.e(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs.
findFitnessDataSources();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i
== GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG,
"Connection lost. Reason: Service Disconnected");
}
}
}
)
.enableAutoManage(this, 0, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.e(TAG, "!_##ERROR :: Google Play services connection failed. Cause: " + result.toString());
}
})
.build();
}
}
private void findFitnessDataSources() {
Fitness.SensorsApi.findDataSources(
mClient,
new DataSourcesRequest.Builder()
.setDataTypes(DataType.TYPE_STEP_COUNT_DELTA)
.setDataSourceTypes(DataSource.TYPE_DERIVED)
.build())
.setResultCallback(new ResultCallback<DataSourcesResult>() {
#Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.e(TAG, "Result: " + dataSourcesResult.getStatus().toString());
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
Log.e(TAG, "Data source found: " + dataSource.toString());
Log.e(TAG, "Data Source type: " + dataSource.getDataType().getName());
//Let's register a listener to receive Activity data!
if (dataSource.getDataType().equals(DataType.TYPE_STEP_COUNT_DELTA) && mListener == null) {
Log.i(TAG, "Data source for TYPE_STEP_COUNT_DELTA found! Registering.");
registerFitnessDataListener(dataSource, DataType.TYPE_STEP_COUNT_DELTA);
}
}
}
});
}
private void registerFitnessDataListener(final DataSource dataSource, DataType dataType) {
// [START register_data_listener]
mListener = new OnDataPointListener() {
#Override
public void onDataPoint(DataPoint dataPoint) {
for (Field field : dataPoint.getDataType().getFields()) {
Value val = dataPoint.getValue(field);
Log.e(TAG, "Detected DataPoint field: " + field.getName());
Log.e(TAG, "Detected DataPoint value: " + val);
}
}
};
Fitness.SensorsApi.add(
mClient,
new SensorRequest.Builder()
.setDataSource(dataSource) // Optional but recommended for custom data sets.
.setDataType(dataType) // Can't be omitted.
.setSamplingRate(1, TimeUnit.SECONDS)
.build(),
mListener).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Listener registered!");
} else {
Log.i(TAG, "Listener not registered.");
}
}
});
}
}
NOTE : :: Sometimes in some device it doestn't detect Step values so whenever you are developing and workling with this code Always Uninstall app and then re-install app. then this works fine.
**Don't forget to add this permission**
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
You can try the StepSensor library from OrangeGangster's.
It contains a custom Service allowing to collect data from the Sensor.TYPE_STEP_COUNTER introduced with Android 4.4 (available only for devices that supports this hardware feature).
This code works for me !
Building the client :
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Invoking Sensors API :
private void invokeSensorsAPI() {
Fitness.SensorsApi.add(
mClient,
new SensorRequest.Builder()
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setSamplingRate(1, TimeUnit.SECONDS)
.build(),
this)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Sensor Listener registered!");
} else {
Log.i(TAG, "Sensor Listener not registered.");
}
}
});
}
Recieving data :
#Override
public void onDataPoint(DataPoint dataPoint) {
for (Field field : dataPoint.getDataType().getFields()) {
Value val = dataPoint.getValue(field);
Log.i(TAG, "Detected DataPoint field: " + field.getName());
Log.i(TAG, "Detected DataPoint value: " + val);
final int value = val.asInt();
if (field.getName().compareToIgnoreCase("steps") == 0) {
runOnUiThread(new Runnable() {
#Override
public void run() {
tv.setText("Value" + value)
}
});
}
}
}
I hope it helps
I think you are making a mistake here
if (resultCode == RESULT_OK) {
// If the user authenticated, try to connect again
mClient.connect()
}
instead it should be
if (resultCode != RESULT_OK) {
// If the user is not authenticated, try to connect again/ resultcode = RESULT_CANCEL
mClient.connect()
} else {
onConnected(null);
}
By your code invokeFitnessApis would never be called because you are reconnecting with googleapiclient after successfull connection.
Related
Can I get the calories and distance using Google Fit Sensor Api?
I write real time fitness app, which should show the current data, which must be updated every second.
I think that using of session Api or History Api in my way is not a good idea.
If I am wrong, please correct me. I could find only manual getting steps in real time
Added:
In code below work only TYPE_STEP_COUNT_CUMULATIVE, for example TYPE_DISTANCE_CUMULATIVE is not working
private void buildFitnessClient() {
if (mClient == null) {
mClient = new GoogleApiClient.Builder(getActivity())
.addApi(Fitness.SENSORS_API)
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
findFitnessDataSources();
}
#Override
public void onConnectionSuspended(int i) {
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i
== GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG,
"Connection lost. Reason: Service Disconnected");
}
}
}
)
.enableAutoManage((MainActivity)getActivity(), 0, new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Google Play services connection failed. Cause: " +
result.toString());
}
})
.build();
}
}
private void findFitnessDataSources() {
Fitness.SensorsApi.findDataSources(mClient, new DataSourcesRequest.Builder()
.setDataTypes(DataType.TYPE_DISTANCE_CUMULATIVE)
.setDataSourceTypes(DataSource.TYPE_RAW)
.build())
.setResultCallback(new ResultCallback<DataSourcesResult>() {
#Override
public void onResult(DataSourcesResult dataSourcesResult) {
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
if (DataType.TYPE_DISTANCE_CUMULATIVE.equals(dataSource.getDataType())) {
registerFitnessDataListener(dataSource, DataType.TYPE_DISTANCE_CUMULATIVE);
}
}
}
});
}
private void registerFitnessDataListener(DataSource dataSource, DataType dataType) {
mListener = new OnDataPointListener() {
#Override
public void onDataPoint(DataPoint dataPoint) {
for (final Field field : dataPoint.getDataType().getFields()) {
final Value val = dataPoint.getValue(field);
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getActivity(), "Field: " + field.getName() + " Value: " + val, Toast.LENGTH_SHORT).show();
}
});
}
}
};
Fitness.SensorsApi.add(
mClient,
new SensorRequest.Builder()
.setDataSource(dataSource)
.setDataType(dataType)
.setSamplingRate(3, TimeUnit.SECONDS)
.build(),
mListener)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Listener registered!");
} else {
Log.i(TAG, "Listener not registered.");
}
}
});
}
YES! You can
Here is the documentation what you can do and can't do. You can also do custom data values also.
After a lot of research, mostly because I can't understand google documentation, I came up with this example:
public class MainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "FitActivity";
//[START Auth_Variable_References]
private static final int REQUEST_OAUTH = 1;
// [END auth_variable_references]
private GoogleApiClient mClient = null;
int mInitialNumberOfSteps = 0;
private TextView mStepsTextView;
private boolean mFirstCount = true;
// Create Builder View
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mStepsTextView = (TextView) findViewById(R.id.steps);
}
private void connectFitness() {
Toast.makeText(this, "connecting", Toast.LENGTH_LONG);
Log.i(TAG, "Connecting...");
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
// select the Fitness API
.addApi(Fitness.SENSORS_API)
.addApi(Fitness.RECORDING_API)
.addApi(Fitness.SESSIONS_API)
.addApi(Fitness.HISTORY_API)
// specify the scopes of access
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
// provide callbacks
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
// Connect the Google API client
mClient.connect();
}
// Manage OAuth authentication
#Override
public void onConnectionFailed(ConnectionResult result) {
Toast.makeText(this, "failed", Toast.LENGTH_LONG);
// Error while connecting. Try to resolve using the pending intent returned.
if (result.getErrorCode() == ConnectionResult.SIGN_IN_REQUIRED ||
result.getErrorCode() == FitnessStatusCodes.NEEDS_OAUTH_PERMISSIONS) {
try {
// Request authentication
result.startResolutionForResult(this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception connecting to the fitness service", e);
}
} else {
Log.e(TAG, "Unknown connection issue. Code = " + result.getErrorCode());
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
if (resultCode == RESULT_OK) {
// If the user authenticated, try to connect again
mClient.connect();
}
}
}
#Override
public void onConnectionSuspended(int i) {
// If your connection gets lost at some point,
// you'll be able to determine the reason and react to it here.
Toast.makeText(this, "suspended", Toast.LENGTH_LONG);
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!");
Toast.makeText(this, "connected", Toast.LENGTH_LONG);
// Now you can make calls to the Fitness APIs.
invokeFitnessAPIs();
}
private void invokeFitnessAPIs() {
getStepsToday();
}
private void getStepsToday() {
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
long startTime = cal.getTimeInMillis();
final DataReadRequest readRequest = new DataReadRequest.Builder()
.read(DataType.TYPE_STEP_COUNT_DELTA)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.build();
DataReadResult dataReadResult =
Fitness.HistoryApi.readData(mClient, readRequest).await(1, TimeUnit.MINUTES);
DataSet stepData = dataReadResult.getDataSet(DataType.TYPE_STEP_COUNT_DELTA);
int totalSteps = 0;
for (DataPoint dp : stepData.getDataPoints()) {
for(Field field : dp.getDataType().getFields()) {
int steps = dp.getValue(field).asInt();
totalSteps += steps;
}
}
TextView steps = (TextView)findViewById(R.id.steps);
steps.setText(totalSteps);
}
// Update the Text Viewer with Counter of Steps..
private void updateTextViewWithStepCounter(final int numberOfSteps) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getBaseContext(), "On Datapoint!", Toast.LENGTH_SHORT);
if(mFirstCount && (numberOfSteps != 0)) {
mInitialNumberOfSteps = numberOfSteps;
mFirstCount = false;
}
if(mStepsTextView != null){
mStepsTextView.setText(String.valueOf(numberOfSteps - mInitialNumberOfSteps));
}
}
});
}
//Start
#Override
protected void onStart() {
super.onStart();
mFirstCount = true;
mInitialNumberOfSteps = 0;
if (mClient == null || !mClient.isConnected()) {
connectFitness();
}
}
//Stop
#Override
protected void onStop() {
super.onStop();
if(mClient.isConnected() || mClient.isConnecting()) mClient.disconnect();
mInitialNumberOfSteps = 0;
mFirstCount = true;
}
I noticed by the logs is that this code don't call any of the google fitmethods. Can somebody help me? Also where do I put my OAuth 2.0 info? I'm really lost in this, even some explanations about the Google API itself would be helpful.
After a lot of research I came up with this recent tutorial and library.
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.
My GoogleApiClient connects successfully and my #Override public void onDataPoint(DataPoint dataPoint) {…} is called exactly once and then never again. This is within a Service that's started only after Google Fit is authorized from within the UI (that's another can of worms). The Service has another GoogleApiClient that successfully runs and is called at my specified interval.
Here's what I see from logcat:
mGoogleFitApiClient connected.
mGoogleFitApiClient listener registered.
mGoogleFitApiClient detected DataPoint: still (100.0% confidence)
It's then never called again and #Override public void onConnectionSuspended(int i) {…} is never called either.
Here's the relevant code from my Service:
private void buildFitnessClient() {
mGoogleFitApiClient = new GoogleApiClient.Builder(this)
.useDefaultAccount()
.addApi(Fitness.SENSORS_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "mGoogleFitApiClient connected.");
setupPhysicalActivityListener();
}
#Override
public void onConnectionSuspended(int i) {
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "mGoogleFitApiClient connection lost. Cause: network lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "mGoogleFitApiClient connection lost. Reason: service disconnected");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "mGoogleFitApiClient connection failed. Cause: " + result.toString());
}
}
)
.build();
}
#Override
public void onDataPoint(DataPoint dataPoint) {
String activityName = "";
float confidence = 0;
for (Field field : dataPoint.getDataType().getFields()) {
if (field.getName().equals("activity")) {
activityName = dataPoint.getValue(field).asActivity();
} else if (field.getName().equals("confidence")) {
confidence = dataPoint.getValue(field).asFloat();
}
}
lastActivityName = activityName;
lastActivityConfidence = confidence;
Log.i(TAG, "mGoogleFitApiClient detected DataPoint: " + activityName + " (" + confidence + "% confidence)");
}
private void setupPhysicalActivityListener() {
SensorRequest sensorRequest = new SensorRequest.Builder()
.setDataType(DataType.TYPE_ACTIVITY_SAMPLE)
.setSamplingRate(15, TimeUnit.SECONDS)
.setFastestRate(5, TimeUnit.SECONDS)
.setAccuracyMode(SensorRequest.ACCURACY_MODE_LOW)
.build();
Fitness.SensorsApi.add(mGoogleFitApiClient, sensorRequest, this)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "mGoogleFitApiClient listener registered.");
} else {
Log.i(TAG, "mGoogleFitApiClient listener not registered.");
}
}
});
}
The request data type is
setDataType(DataType.TYPE_ACTIVITY_SAMPLE)
Try
DataType.TYPE_STEP_COUNT_DELTA or DataType.TYPE_HEART_RATE_BPM
to see if you get the same result.(only called once)
Could it be because the screen becomes locked?
I have the following code where it does two main things.
It connects to google play services.
Inside the onConnected() method a service is started, by calling the startService(...) method.
When I run the program I get the following log message.
Connected!!!
Fit wasn't able to connect, so the request failed.
GoogleFitService destroyed.
Here is my code:
public class MainActivity extends ActionBarActivity {
public final static String TAG = "GoogleFitService";
private static final int REQUEST_OAUTH = 1;
private static final String AUTH_PENDING = "auth_state_pending";
private boolean authInProgress = false;
private GoogleApiClient mClient = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buildFitnessClient();
}
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.API)
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs.
// Put application specific code here.
Intent service = new Intent(MainActivity.this,
GoogleFitService.class);
service.putExtra(GoogleFitService.SERVICE_REQUEST_TYPE,
GoogleFitService.TYPE_REQUEST_CONNECTION);
startService(service);
}
#Override
public void onConnectionSuspended(int i) {
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), MainActivity.this, 0).show();
return;
}
if (!authInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.startResolutionForResult(MainActivity.this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
}
}
)
.build();
}
#Override
protected void onStart() {
super.onStart();
// Connect to the Fitness API
Log.i(TAG, "Connecting...");
mClient.connect();
Intent service = new Intent(this, GoogleFitService.class);
service.putExtra(GoogleFitService.SERVICE_REQUEST_TYPE, GoogleFitService.TYPE_REQUEST_CONNECTION);
startService(service);
}
#Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.isConnecting() && !mClient.isConnected()) {
mClient.connect();
}
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(AUTH_PENDING, authInProgress);
}
}
And the second class is basically an Intent service. Maybe the mistake is here.
public class GoogleFitService extends IntentService {
public static final String TAG = "GoogleFitService";
private GoogleApiClient mGoogleApiFitnessClient;
private boolean mTryingToConnect = false;
public static final String SERVICE_REQUEST_TYPE = "requestType";
public static final int TYPE_GET_STEP_TODAY_DATA = 1;
public static final int TYPE_REQUEST_CONNECTION = 2;
public static final String HISTORY_INTENT = "fitHistory";
public static final String HISTORY_EXTRA_STEPS_TODAY = "stepsToday";
public static final String FIT_NOTIFY_INTENT = "fitStatusUpdateIntent";
public static final String FIT_EXTRA_CONNECTION_MESSAGE =
"fitFirstConnection";
public static final String FIT_EXTRA_NOTIFY_FAILED_STATUS_CODE =
"fitExtraFailedStatusCode";
public static final String FIT_EXTRA_NOTIFY_FAILED_INTENT =
"fitExtraFailedIntent";
#Override
public void onDestroy() {
Log.d(TAG, "GoogleFitService destroyed");
if (mGoogleApiFitnessClient.isConnected()) {
Log.d(TAG, "Disconecting Google Fit.");
mGoogleApiFitnessClient.disconnect();
}
super.onDestroy();
}
#Override
public void onCreate() {
super.onCreate();
buildFitnessClient();
Log.d(TAG, "GoogleFitService created");
}
public GoogleFitService() {
super("GoogleFitService");
}
#Override
protected void onHandleIntent(Intent intent) {
//Get the request type
int type = intent.getIntExtra(SERVICE_REQUEST_TYPE, 1);
//block until google fit connects. Give up after 10 seconds.
if (!mGoogleApiFitnessClient.isConnected()) {
mTryingToConnect = true;
mGoogleApiFitnessClient.connect();
//Wait until the service either connects or fails to connect
while (mTryingToConnect) {
try {
Thread.sleep(100, 0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (mGoogleApiFitnessClient.isConnected()) {
if (type == TYPE_GET_STEP_TODAY_DATA) {
Log.d(TAG, "Requesting steps from Google Fit");
getStepsToday();
Log.d(TAG, "Fit update complete. Allowing Android to destroy
the service.");
} else if (type == TYPE_REQUEST_CONNECTION) {
}
} else {
//Not connected
Log.w(TAG, "Fit wasn't able to connect, so the request failed.");
}
}
private void getStepsToday() {
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
long startTime = cal.getTimeInMillis();
final DataReadRequest readRequest = new DataReadRequest.Builder()
.read(DataType.TYPE_STEP_COUNT_DELTA)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.build();
DataReadResult dataReadResult =
Fitness.HistoryApi.readData(mGoogleApiFitnessClient,
readRequest).await(1, TimeUnit.MINUTES);
DataSet stepData =
dataReadResult.getDataSet(DataType.TYPE_STEP_COUNT_DELTA);
int totalSteps = 0;
for (DataPoint dp : stepData.getDataPoints()) {
for (Field field : dp.getDataType().getFields()) {
int steps = dp.getValue(field).asInt();
totalSteps += steps;
}
}
publishTodaysStepData(totalSteps);
}
private void publishTodaysStepData(int totalSteps) {
Intent intent = new Intent(HISTORY_INTENT);
// You can also include some extra data.
intent.putExtra(HISTORY_EXTRA_STEPS_TODAY, totalSteps);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void buildFitnessClient() {
// Create the Google API Client
mGoogleApiFitnessClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.API)
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Google Fit connected.");
mTryingToConnect = false;
Log.d(TAG, "Notifying the UI that we're
connected.");
notifyUiFitConnected();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at
some point,
mTryingToConnect = false;
if (i ==
GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Google Fit Connection lost.
Cause:Network Lost.");
} else if (i ==
GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Google Fit Connection lost.
Reason:Service Disconnected ");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult
result) {
mTryingToConnect = false;
notifyUiFailedConnection(result);
}
}
)
.build();
}
private void notifyUiFitConnected() {
Intent intent = new Intent(FIT_NOTIFY_INTENT);
intent.putExtra(FIT_EXTRA_CONNECTION_MESSAGE,
FIT_EXTRA_CONNECTION_MESSAGE);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void notifyUiFailedConnection(ConnectionResult result) {
Intent intent = new Intent(FIT_NOTIFY_INTENT);
intent.putExtra(FIT_EXTRA_NOTIFY_FAILED_STATUS_CODE,
result.getErrorCode());
intent.putExtra(FIT_EXTRA_NOTIFY_FAILED_INTENT, result.getResolution());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
Any ideas what might went wrong? Thanks, Theo.
You need to access those detail from fit only when it connected .And Try this
public void buildFitnessClient() {
fitnessClient = new GoogleApiClient.Builder(context)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.SESSIONS_API)
.addApi(Fitness.RECORDING_API)
.addScope(new Scope(Scopes.FITNESS_BODY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_NUTRITION_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
ReferenceWrapper.getInstance(context).setApiClient(fitnessClient);
((OnClientConnectListener) context).onclientConnected();
}
#Override
public void onConnectionSuspended(int i) {
}
})
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(
ConnectionResult result) {
if (!result.hasResolution()) {
GooglePlayServicesUtil.getErrorDialog(
result.getErrorCode(), context, 0)
.show();
return;
}
if (!authInProgress) {
try {
authInProgress = true;
result.startResolutionForResult(
context,
KeyConstant.REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
}
}
}
}).build();
}
And at first you need to register your application on google api console . Generate an outh2 client id from there and enable fitness api . Search for fitness Api in api Dashboard , and enable it.. And override OnActivityresult
in your Activity .
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == KeyConstant.REQUEST_OAUTH) {
fitnessHelper.setAuthInProgress(false);
if (resultCode == Activity.RESULT_OK) {
if (!fitnessHelper.isConnecting() && !fitnessHelper.isConnected()) {
fitnessHelper.connect();
}
}
}
}