GooglePlayServices recently changed from the way you detect the users activity - from using ActivityRecognitionClient to ActivityRecognitionApi. I have followed all the examples I can find but must have missed something.
After making the call to GoogleApiClient.Builder(mContext).addApi(ActivityRecognition.API)...build() I was expecting that one of the connection callback methods would be called. I have logging and breakpoints in all the callback methods but none of them are ever called.
OnReceive() and CallClient() are called as expected and the manifest file includes: uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"
What am I missing? I would love to get to the bottom of this given the amount of time I have wasted so far.
(P.S. It's my own Logging library - it is not part of the issue)
public class BootAtStartupReceiver extends BroadcastReceiver implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private final String TAG = getClass().getName();
private PendingIntent mpIntent;
private static GoogleApiClient mGoogleApiClient;
private Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onReceive: " + intent.getAction());
if ((intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) || (intent.getAction().equals(BroadcastIntentConstants.ACTIVITY_FIRST_TIME_CALL_SERVICE)))
{
mContext = context;
callClient();
}
}
private void callClient() {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside callClient");
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
if (resp == ConnectionResult.SUCCESS) {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
} else {
Logging.log(Logging.enumLoggingLevel.e, getClass().getName(), "Google play Services are not available.");
}
}
#Override
public void onConnected(Bundle bundle) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnected");
Intent intent = new Intent(mContext, ActivityRecognitionIntentService.class);
mpIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, 1000, mpIntent);
}
#Override
public void onDisconnected() {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onDisconnected");
}
#Override
public void onConnectionSuspended(int i) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnectionSuspended");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnectionFailed");
}
}
Are you missing the call to connect() after the build? The callbacks dont fire unless you call connect.
mGoogleApiClient.connect()
Related
I have implemented Google Location Services inside a service, so that I can get location updates in the background (so that updates don't stop when user locks screen, switches fragment, etc.). But I am getting a strange error message that is stopping me from implementing it.
On the line:
"LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);"
It is telling me that 2rd parameter 'this' is not allowed and should be cast to (com.google.android.gms.location.LocationListener). But in every example I've seen this is not the case. When I do cast it, it does not work
Below is my code, trouble is in the onConnected method
public class LocationTrackingService extends Service implements LocationListener, ConnectionCallbacks, OnConnectionFailedListener {
GoogleApiClient googleApiClient = null;
LocationRequest locationRequest;
Location currentLocation;
static final int INTERVAL = 2000;
static final int FASTEST_INTERVAL = 500;
static final int PRIORITY = LocationRequest.PRIORITY_HIGH_ACCURACY;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
setupGoogleApiClient();
createLocationRequest(INTERVAL, FASTEST_INTERVAL, PRIORITY);
googleApiClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!googleApiClient.isConnected()) {
googleApiClient.connect();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
//TODO maybe dont need this
googleApiClient.disconnect();
super.onDestroy();
}
#Override
public void onLocationChanged(Location location) {
//updating current location
currentLocation = location;
//TODO will be writing directly to database here
//broadcasting intent
Intent publishLocationUpdate = new Intent("location_update");
publishLocationUpdate.putExtra("current_location", currentLocation);
sendBroadcast(publishLocationUpdate);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
//if location tracking is not enabled
#Override
public void onProviderDisabled(String s) {
Intent toSettings = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
toSettings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(toSettings);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
//sets location to last known location
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
currentLocation = FusedLocationApi.getLastLocation(googleApiClient);
//request updates
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
// Create an instance of GoogleAPIClient which we call to recieve location information
void setupGoogleApiClient(){
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
//set request settings, interval: how soon until new request is made, priority affects batterylife (using GPS, netowork, data...)
void createLocationRequest(int interval, int fastestInterval, int priority) {
locationRequest = new LocationRequest();
locationRequest.setInterval(interval);
locationRequest.setFastestInterval(fastestInterval);
locationRequest.setPriority(priority);
//can also use PRIORITY_LOW_POWER, PRIORITY_BALANACED_POWER_ACCURACY, PRIORITY_NO_POWER
}
}
I check the intent in onResume in my fragment, code below:
if(broadcastReceiver == null){
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Location currentLocation;
currentLocation = (Location) intent.getExtras().get("current_location");
currentAltitudeTextView.setText(String.valueOf(currentLocation.getLatitude()));
currentSpeedTextView.setText(String.valueOf(currentLocation.getLongitude()));
}
};
}
context.registerReceiver(broadcastReceiver, new IntentFilter("location_update"));
My app is like a tracker. It saves user locations, then sends it to server.
I made this server foreground and sticky. On samsung s4 everything works fine, but on huawei honor 4c service gets killed as fast as i lock screen. Moreover, methods like onDestroy() are not called. If i add app to "Protected apps" it lives more, but nearly 30-45 mins. Is there a way to keep my service alive? Or is there a way to solve my problem without foreground service? I searched tons of posts about this problem, but didnt find solution.
Here is my service
public class LocationService extends Service {
private static final long TIME_BETWEEN_LOCATION_SEND_IN_MILLIS = 60 * 1000;
private static final long TIME_BETWEEN_LOCATION_UPDATES = 10 * 1000;
private List<Location> locations;
private int NOTIFICATION_ID = 31337;
private boolean isAlreadyRunning = false;
public boolean Continue = true;
private GoogleApiClient googleApiClient;
#Override
public void onCreate() {
super.onCreate();
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(getApplicationContext());
googleApiClient = builder
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.wtf("lol", "connected");
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(TIME_BETWEEN_LOCATION_UPDATES);
locationRequest.setFastestInterval(TIME_BETWEEN_LOCATION_UPDATES);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//noinspection MissingPermission
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, locationRequest, new LocationListener() {
#Override
public void onLocationChanged(Location location) {
locations.add(location);
}
});
}
#Override
public void onConnectionSuspended(int i) {
Log.wtf("lol", "connection suspended");
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(
#NonNull ConnectionResult connectionResult
) {
Log.wtf("lol", "connection Failed");
}
})
.addApi(LocationServices.API)
.build();
locations = new ArrayList<>();
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.wtf("lol","service onlow");
}
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
Log.wtf("lol","service ontrim");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.wtf("lol","service ontaskremoved");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.wtf("lol", "service OnStartCommand");
if (!isAlreadyRunning) {
Intent resultIntent = new Intent(getApplicationContext(), MainActivity.class);
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent resultPendingIntent = PendingIntent.getActivity(
this,
333,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Title")
.setContentText("Explanation!")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(resultPendingIntent);
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
googleApiClient.connect();
isAlreadyRunning = true;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (locations.size() > 0) {
sendLocationsAndClearList();
}
if(Continue){
handler.postDelayed(this,TIME_BETWEEN_LOCATION_SEND_IN_MILLIS);
}
}
},TIME_BETWEEN_LOCATION_SEND_IN_MILLIS);
}
return Service.START_STICKY;
}
#Override
public void onDestroy() {
Log.wtf("lol", "service onDestroy");
Continue = false;
googleApiClient.disconnect();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You also have to create a CPU wake lock. The CPU can tear down to a low power mode which will stop your app process. It may resume if the CPU powers up again for some reason.
Have a look for the WAKE LOCK topic in the Android documentation.
TL;DR see below
A core feature of my android application is to broadcast the user's current location in a foreground service that continues to run after being unbound from the activity. I have everything working fine in terms of publishing to a channel and subscribers receiving the data from the channel. The service is working great. I'm even animating a google maps camera to follow the location received from the subscribed message.
My concern is that I'm getting this message:
I/Choreographer: Skipped 49 frames! The application may be doing too much work on its main thread.
I have of course researched this message. A lot of people seem to say it has something to do with animation, so I assume it has something to do with the map since it is the only thing animating. Though, I've also learned that the choreographer can produce this message because of other reasons.
When my application starts up, it launches a foreground service which connects to google location services using the GoogleAPIClient. After initialization, I immediately request my current location and use PubNub to broadcast the lng and lat to a channel. I then subcribe to that channel and when the message is received my MapFragmentPresenter class listens to location updates from the service. The presenter then calls the MapFragment's View (The V in MVP) to animate the camera and position the marker on each new location.
This is all working fine. I just want to make sure I'm not causing skipped frames and not putting too much work on the main thread. I'm doing very little on the main thread right now considering all the other stuff I have planned on doing on it. Right now I'm just continually repositioning the camera to follow the device's current location, pretty basic I would think.
Also, I am not using any wakelock features, yet my PubNub broadcasts are working fine. Why is this? I read somewhere that using PubNub running while the device is locked requires this, but mine is working without it.
Sorry for the long post.
Note: I do not have large resource files. I haven't even really added anything other than icons I import from AS itself.
TL;DR
I seem to be doing too much on my main thread. Can google location services and PubNub operations be done on different threads in a service and will this fix my problem?
Questions:
Should/Can I do all of the location requests on a worker thread?
Should/Can PubNub operations be on their own thread?
Is anything I'm doing bad?
My foreground service seems to be working perfectly fine while the device is asleep/locked, but I have NOT messed with WAKE_LOCK at all. Should I? What's the difference in manipulating state of lock when my service seems to be doing everything I expect?
Here's some of the code:
Thanks for taking the time!
MapViewFragment
public class MapViewFragment extends Fragment
implements OnMapReadyCallback, IMapFragment {
private static final String TAG = "MAP_VIEW_FRAGMENT";
private MapView mapView;
private GoogleMap gMap;
private IMapPresenter presenter;
private boolean mapReady;
private Handler handler;
private LatLng myLocation;
//ToDo: newInstance method
//==========================
//Fragment Lifecycle
//==========================
#Override #Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
mapReady = false;
presenter = new MapPresenter(this);
View v = inflater.inflate(R.layout.map_view, container, false);
handler = new Handler(Looper.getMainLooper());
mapView = (MapView) v.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
return v;
}
#Override
public void onResume() {
super.onResume();
mapView.onResume();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
public MapPresenter getPresenter(){
return (MapPresenter) presenter;
}
//==========================
//Map
//==========================
#Override
public void onMapReady(GoogleMap googleMap) {
this.gMap = googleMap;
mapReady = true;
}
#Override
public void moveToMyLocation(final LatLng locData) {
handler.post(new Runnable() {
#Override
public void run() {
gMap.addMarker(new MarkerOptions().position(locData).title("myLocation"));
gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(locData,20));
Log.d(TAG,"//////////////////moveToMyLocation");
}
});
}
}
Service
public class MapService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "MAP_VIEW_SERVICE";
private int REQUEST_CODE = 101;
private int NOTIFICATION_ID = 102;
private LocationRequest gLocationRequest;
private GoogleApiClient gApiClient;
private Pubnub mPubnub;
private Location lastLocation;
private String mapFragTag;
private final IBinder mBinder = new LocalBinder();
private LatLng mLatLng;
private ServiceRequestListener requestListener;
//==========================
//Service Lifecycle
//==========================
#Override
public void onCreate() {
super.onCreate();
gLocationRequest = LocationRequest.create();
gLocationRequest.setInterval(5000);
gLocationRequest.setFastestInterval(5000);
gLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
gApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mPubnub = new Pubnub(
getString(R.string.pubnub_publish_key)
,getString(R.string.pubnub_subscribe_key));
try{
mPubnub.subscribe("Channel-d2160eqlk",subscribeCallback);
}catch (PubnubException e) {
Log.e("**MapService**", e.toString());
}
gApiClient.connect();
setupAndLaunchForeground();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Nullable #Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onDestroy() {
super.onDestroy();
if(gApiClient.isConnected()) {
gApiClient.disconnect();
}
}
public void setRequestListener(ServiceRequestListener requestListener) {
this.requestListener = requestListener;
}
//==========================
//StartForeground
//==========================
private void setupAndLaunchForeground() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Service Running")
.setTicker("AppName Services Initiated")
.setWhen(System.currentTimeMillis())
.setOngoing(true);
Intent startIntent = new Intent(this, MapViewFragment.class);
PendingIntent contentIntent = PendingIntent.getActivity(this,
REQUEST_CODE, startIntent, 0);
builder.setContentIntent(contentIntent);
Notification notification = builder.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notification);
startForeground(NOTIFICATION_ID,notification);
}
//==========================
//Google API Client
//==========================
#Override
public void onConnected(#Nullable Bundle bundle) {
PackageManager manager = getPackageManager();
if(manager.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION,"com.firsttread.appname")
== PackageManager.PERMISSION_GRANTED){
LocationServices.FusedLocationApi.requestLocationUpdates(gApiClient, gLocationRequest, this);
lastLocation = LocationServices.FusedLocationApi.getLastLocation(gApiClient);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
//==========================
//Location
//==========================
#Override
public void onLocationChanged(Location location) {
broadcastLocation(location);
this.lastLocation = location;
Log.d("****LocationChange****","Lat: " + location.getLatitude() + "Lng: " + location.getLongitude());
}
//==========================
//PubNub
//==========================
private void broadcastLocation(Location location){
JSONObject message = new JSONObject();
try{
message.put("lat", location.getLatitude());
message.put("lng", location.getLongitude());
}catch (JSONException e){
Log.e("MapService", e.toString());
}
mPubnub.publish("ChannelName", message, publishCallback);
}
Callback publishCallback = new Callback() {
#Override
public void successCallback(String channel, Object response) {
Log.d("**PUBNUB**", response.toString());
}
#Override
public void errorCallback(String channel, PubnubError error) {
Log.e("**PUBNUB**", error.toString());
}
};
Callback subscribeCallback = new Callback() {
#Override
public void successCallback(String channel, Object message) {
JSONObject jsonMessage = (JSONObject) message;
try {
double mLat = jsonMessage.getDouble("lat");
double mLng = jsonMessage.getDouble("lng");
if(requestListener != null){
sendLocation(new LatLng(mLat,mLng));
}
} catch (JSONException e) {
Log.e("**PUBNUB_ERROR**", e.toString());
}
}
};
//==========================
//Location Data Methods
//==========================
private void sendLocation(LatLng locData){
requestListener.retrieveLocation(locData);
}
//==========================
//MapInterface
//==========================
public interface ServiceRequestListener {
void retrieveAppNameLocations(HashMap<String,Long> memberLocations);
void retrieveLocation(LatLng locData);
}
//==========================
//ServiceBinder
//==========================
public class LocalBinder extends Binder {
public MapService getService() {
return MapService.this;
}
}
}
Some answers to your questions:
1. Should/Can I do all of the location requests on a worker thread?
You shouldn't need to do anything special other than just subscribe to the channel that will have the location data published to it.
2. Should/Can PubNub operations be on their own thread?
They will be, just use the async APIs, not the sync APIs (you can't use sync in Android anyways without extra work, otherwise Android will throw exception).
3. Is anything I'm doing bad? My foreground service seems to be working perfectly fine while the device is asleep/locked, but I have NOT messed with WAKE_LOCK at all. Should I?
At the time you asked this question, you might have been able config the WAKE_LOCK but might not be permitted anymore in lates Android OS (without additional permissions from end user, perhaps) but shouldn't matter. Just use push notifications when app is in background.
4. What's the difference in manipulating state of lock when my service seems to be doing everything I expect?
Not really sure what you mean here so would need more details.
If you are still having issues with the above, please submit full details to PubNub Support. Send sample project zipped (if possible), your PubNub sub-key and PubNub SDK logs that captures any scenarios you are having issues with.
Was working when I was using GoogleApiClient in an Activity but moved it to a Service and the onConnected is not being called.
public class StepsMonitoringService extends Service implements GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mClient;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mClient = new GoogleApiClient.Builder(this).addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addConnectionCallbacks(this).build();
mClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mClient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
// NOT being called!! WHY??
}
#Override
public void onConnectionSuspended(int cause) {
}
}
Any ideas anyone? What am I doing wrong? Has anyone got GoogleApiClient working in a Service?
The service is called from an Activity
public class MainActivity extends FragmentActivity {
private TextView mStepsView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, StepsMonitoringService.class);
startService(intent);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("StepMonitoringServiceIntent"));
mStepsView = (TextView) findViewById(R.id.steps);
}
private void displayOnUI(String msg) {
mStepsView.setText(msg + "\n" + mStepsView.getText());
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long steps = intent.getLongExtra("steps", 0);
displayOnUI(steps + " steps");
}
};
}
During debugging I can see the onCreate of the Service gets called, however the onConnected is never called. Nothing special in the logs from what I can see.
First implement these interfaces:
GoogleApiClient.ConnectionCallbacks
GoogleApiClient.OnConnectionFailedListener
Then you will have to add these methods to your class:
public void onConnected(final Bundle bundle)
public void onConnectionSuspended(final int i)
public void onConnectionFailed(final ConnectionResult connectionResult)
As soon as you connect, the OnConnected method will be called. In this method can you do whatever you want, like getting the current location, the location address, add a marker point to map, etc.
But you cannot do anything without establishing a connection to the Google API client.
To connect to the GoogleAPIClient, you can add this method to your class and call it in your onCreate method.
private synchronized void buildGoogleAPIClient(){
googleApiclient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
googleApiclient.connect();
Toast.makeText(getActivity(), "connected", Toast.LENGTH_SHORT).show();
}
Add addOnConnectionFailedListener to GoogleApiClient to track the error. As per doc addOnConnectionFailedListener called when there was an error connecting the client to the service.
public class StepsMonitoringService extends Service implements GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mClient;
#Override
public void onCreate() {
super.onCreate();
mClient = new GoogleApiClient.Builder(this).addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
.addConnectionCallbacks(this)
//Add Connection Failed Listener to track error.
.addOnConnectionFailedListener(this)
.build();
mClient.connect();
}
#Override
public void onConnected(Bundle connectionHint) {
// NOT being called!! WHY??
}
#Override
public void onConnectionSuspended(int cause) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
//Called called when there was an error connecting the client to the service.
Log.i(LOG_TAG,"onConnectionFailed:"+connectionResult.getErrorCode()+","+connectionResult.getErrorMessage());
}
}
try this.
public class StepsMonitoringService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mClient;
/**
* Builds a GoogleApiClient. Uses the addApi() method to request the
* Fitness API.
*/
protected synchronized void buildGoogleApiClient() {
mClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Fitness.HISTORY_API)
.build();
}
#Override
public void onCreate() {
super.onCreate();
if (mClient == null) {
buildGoogleApiClient();
}
mClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onConnected(Bundle connectionHint) {
// NOT being called!! WHY??
}
#Override
public void onConnectionSuspended(int cause) {
mClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// Called called when there was an error connecting the client to the
// service.
Log.i(LOG_TAG,
"onConnectionFailed:" + connectionResult.getErrorCode() + "," + connectionResult.getErrorMessage());
}
}
I had a same issue when I was using useDefaultAccount() to create a client. I then replaced it with setAccountName() and it starts working. I think for some reasons accountpicker doesn't work in service that's why googleapiclient's connect() silently failed since you need specify which account you use for retrieving Fitness info. Noted that you need to have an account picker in your activity and pass the email account to your service in some way.
I'm registering my app after boot to receive location updates. My boot receiver is starting a service that does the initialization:
#Override
protected void onHandleIntent(Intent intent) {
GoogleApiClient client = _googleApiBuilder.get()
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
client.connect();
}
Sometimes in the onConnected callback method I'm getting exception indication I'm not connected yet. After some research I've encountered this - GoogleApiClient is throwing "GoogleApiClient is not connected yet" AFTER onConnected function getting called
It made me think, does the way I'm initializing google api is correct ? e.g. should I initialize it in a service ?
What is the suggested way to do it in the background ?
Hope it will be helpful to you.
public class LocationService extends Service implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener {
private static final String TAG = LocationService.class.getSimpleName();
private GoogleApiClient mGoogleApiClient;
#Override
public IBinder onBind(final Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
initGoogleApi();
}
#Override
public int onStartCommand(final Intent intent, final int flags,
final int startId) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onLocationChanged(final Location location) {
}
#Override
public void onConnectionFailed(final ConnectionResult result) {
}
#Override
public void onConnected(final Bundle bundale) {
createLocationRequest();
}
#Override
public void onConnectionSuspended(final int arg0) {
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
protected void createLocationRequest() {
final LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(Constants.INTERVAL);
mLocationRequest.setFastestInterval(Constants.FAST_INTERVAL);
mLocationRequest
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mLocationRequest.setSmallestDisplacement(0);
startLocationUpdates(mLocationRequest);
}
private void initGoogleApi() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
}
}
Used the following solution instead:
googleApiInstance.blockingConnect(10, TimeUnit.SECONDS);
or in other words instead of running the operation in a different thread (that's what connect is doing), I'm running it in my own thread (I'm using IntentService) and manage the connection life cycle on my own.