android detect ActivityRecognition in background - android

I`d like to detect user user's activity in background when app is closed. There is an example of using ActivityRecognition from Google APIs for Android.
In the example the recognition is initiated by an Activity, and I made my service realization.
It works fine on most devices but not on devices with api 4.2.x.
public class RecognitionService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ResultCallback<Status> {
private static final String TAG = RecognitionService.class.getSimpleName();
public final static int DETECTION_INTERVAL_IN_MILLISECONDS = 60_000;
private GoogleApiClient googleApiClient;
public RecognitionService() {
super();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
initLocationClient();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void initLocationClient() {
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient
.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(ActivityRecognition.API)
.build();
}
if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) {
googleApiClient.connect();
}
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected to GoogleApiClient");
if (googleApiClient != null && googleApiClient.isConnected()) {
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(
googleApiClient,
DETECTION_INTERVAL_IN_MILLISECONDS,
getActivityDetectionPendingIntent()
).setResultCallback(this);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection suspended");
googleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
}
private PendingIntent getActivityDetectionPendingIntent() {
Intent intent = new Intent(this, DetectedActivitiesIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// requestActivityUpdates() and removeActivityUpdates().
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
#Override
public void onResult(Status status) {
Log.i(TAG, "onResult = " + status.getStatusMessage());
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(
googleApiClient,
getActivityDetectionPendingIntent()
).setResultCallback(this);
}
}
Methods onConnected, onConnectionSuspended, onConnectionFailed are not called.
Do you have any ideas about this case?

Confirm that the device has the the correct version of GooglePlayServices installed using isGooglePlayServicesAvailable():
GoogleApiAvailability apiAvail = GoogleApiAvailability.getInstance();
int errorCode = apiAvail.isGooglePlayServicesAvailable(this);
if (errorCode == ConnectionResult.SUCCESS) {
// okay
} else {
// not available; start processing to resolve
}
Although unavailability of Play Services should be reported after a connection request to onConnectionFailed(), using isGooglePlayServicesAvailable() offers another means to check availability.
This SO question addresses version support for ActivityRecognition.

Related

Awareness API delays activity callbacks significantly

I've created a class and a BroadcastReceiver to get callbacks from the awareness api for when walking or running ends.
I wasn't getting timely callbacks and at first thought it was because I had registered a 'stopping' callback, but then after setting my phone down for a bit, I did get several callbacks! But this was far far from the time I'd stopped walking. At least 5 minutes after stopping.
Sometimes I don't get callbacks even when the Google Fit app records activity.
Since I have gotten callbacks at least a few times I know the registration is ok. Why are the calls this delayed and sometimes missing?
For background reference, I'm registering these callbacks in the onStart on the main activty, i.e initiateAwareness is called at that time, within the onstart on an activity. And i never unregister them.
I don't intend to use it this way in production, it was just for testing. Plus my inital attempt of registering the fences with an application context failed.
Here's the helper class I made to set up the registration of the google client and fences.
public class AwarenessHelper {
public static final String WALKING_ENDED_FENCE = "walkingEndedKey";
public static final String RUNNING_ENDED_FENCE = "runningEndedKey";
public static final String TYPE_2_WALKING = "duringWalkingKey";
public static final String TYPE_2_RUNNING = "duringRunningKey";
private String tag = AwarenessHelper.class.getSimpleName();
public void initiateAwareness(final Activity context)
{
final GoogleApiClient googleApiClient = buildClient(context);
Log.d(tag, "Initiating blocking connect");
googleApiClient.registerConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
if ( googleApiClient.isConnected() )
{
Log.d(tag, "Client connected, initiating awareness fence registration");
registerAwarenessFences(context, googleApiClient);
}
else
{
Log.d(tag, "Couldn't connect");
}
}
#Override
public void onConnectionSuspended(int i) {
}
});
googleApiClient.connect();
}
private void registerAwarenessFences(Context context, GoogleApiClient mGoogleApiClient) {
Awareness.FenceApi.updateFences(
mGoogleApiClient,
new FenceUpdateRequest.Builder()
.addFence(WALKING_ENDED_FENCE, DetectedActivityFence.stopping(DetectedActivityFence.WALKING), getBroadcastPendingIntent(context))
.addFence(RUNNING_ENDED_FENCE, DetectedActivityFence.stopping(DetectedActivityFence.RUNNING), getBroadcastPendingIntent(context))
.addFence(TYPE_2_WALKING, DetectedActivityFence.during(DetectedActivityFence.WALKING), getBroadcastPendingIntent(context))
.addFence(TYPE_2_RUNNING, DetectedActivityFence.stopping(DetectedActivityFence.RUNNING), getBroadcastPendingIntent(context))
.build())
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Log.i(tag, "Fence was successfully registered.");
} else {
Log.e(tag, "Fence could not be registered: " + status);
}
}
});
}
private GoogleApiClient buildClient(final Activity activity)
{
GoogleApiClient client = new GoogleApiClient.Builder(activity)
.addApi(Awareness.API)
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
if ( connectionResult.hasResolution() && connectionResult.getErrorCode() == CommonStatusCodes.SIGN_IN_REQUIRED )
{
try {
connectionResult.startResolutionForResult(activity, GOOGLE_FIT_AUTHORIZATION_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
}
})
.build();
return client;
}
private PendingIntent getBroadcastPendingIntent(Context context)
{
Intent intent = new Intent(AWARENESS_BROADCAST_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
return pendingIntent;
}
}
Here's the BroadcastReceiver:
public class AwarenessHelper {
public static final String WALKING_ENDED_FENCE = "walkingEndedKey";
public static final String RUNNING_ENDED_FENCE = "runningEndedKey";
public static final String TYPE_2_WALKING = "duringWalkingKey";
public static final String TYPE_2_RUNNING = "duringRunningKey";
private String tag = AwarenessHelper.class.getSimpleName();
public void initiateAwareness(final Activity context)
{
final GoogleApiClient googleApiClient = buildClient(context);
Log.d(tag, "Initiating blocking connect");
googleApiClient.registerConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(#Nullable Bundle bundle) {
if ( googleApiClient.isConnected() )
{
Log.d(tag, "Client connected, initiating awareness fence registration");
registerAwarenessFences(context, googleApiClient);
}
else
{
Log.d(tag, "Couldn't connect");
}
}
#Override
public void onConnectionSuspended(int i) {
}
});
googleApiClient.connect();
}
private void registerAwarenessFences(Context context, GoogleApiClient mGoogleApiClient) {
Awareness.FenceApi.updateFences(
mGoogleApiClient,
new FenceUpdateRequest.Builder()
.addFence(WALKING_ENDED_FENCE, DetectedActivityFence.stopping(DetectedActivityFence.WALKING), getBroadcastPendingIntent(context))
.addFence(RUNNING_ENDED_FENCE, DetectedActivityFence.stopping(DetectedActivityFence.RUNNING), getBroadcastPendingIntent(context))
.addFence(TYPE_2_WALKING, DetectedActivityFence.during(DetectedActivityFence.WALKING), getBroadcastPendingIntent(context))
.addFence(TYPE_2_RUNNING, DetectedActivityFence.stopping(DetectedActivityFence.RUNNING), getBroadcastPendingIntent(context))
.build())
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Log.i(tag, "Fence was successfully registered.");
} else {
Log.e(tag, "Fence could not be registered: " + status);
}
}
});
}
private GoogleApiClient buildClient(final Activity activity)
{
GoogleApiClient client = new GoogleApiClient.Builder(activity)
.addApi(Awareness.API)
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
if ( connectionResult.hasResolution() && connectionResult.getErrorCode() == CommonStatusCodes.SIGN_IN_REQUIRED )
{
try {
connectionResult.startResolutionForResult(activity, GOOGLE_FIT_AUTHORIZATION_REQUEST_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
}
})
.build();
return client;
}
private PendingIntent getBroadcastPendingIntent(Context context)
{
Intent intent = new Intent(AWARENESS_BROADCAST_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
return pendingIntent;
}
}
I get the notifications, but after a massive delay and sometimes not at all.
I am starting the Activity many times, so perhaps the fences are being registered over and over? Is that a relevant fact?
Also is a service or broadcast receiver context appropriate for the initialisation of awareness clients and fences?
Awareness subscribes to get ActivityRecognition updates rather infrequently, so it is not very unexpected that you get a response after a few minutes.
You should also worry about having too many fences without unregistering in general.
Also there is no reason to have a separate pendingIntent for each of your fences; you could have a single pendingIntent and add all fences against that one. Use fence key extra to distinguish results of each fence. And again, do unregister when it makes sense. Otherwise, the fences could hang around even after your app goes away.

creating geofences in background service

I'm making an android application in which want to create a Geofence at LatLong coordinates specified at my server.
The coordinates are getting updated periodically in background from within a service. I'm reading these coordinates and wish to create a Geofence for it in background without user intervention. I tried doing so within a service but it's not working. I can get the coordinates from the server at regular intervals but I'm not able to create Geofence for it, getting a nullPointerException.
However, I'm able to create Geofences in an Activity on click of a button(hardcoding LatLong coordinates) but its not working in a service.
My service:
public class GPSPollingService extends Service implements ResultCallback<Status>, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleApiClient;
private PowerManager.WakeLock mWakeLock;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
private final String TAG = "GPSPollingService";
private PendingIntent mGeofencePendingIntent;
String url = "http://shielded.coolpage.biz/status_read.php";
private static final int REQUEST_CODE_LOCATION = 2;
private Boolean servicesAvailable = false;
private Activity mActivity;
ArrayList<Geofence> mCurrentGeofences = new ArrayList<Geofence>();;
RequestQueue requestQueue;
Location mLocation;
public GPSPollingService(){}
public GPSPollingService(Activity mActivity){
super();
this.mActivity = mActivity;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mInProgress = false;
requestQueue = Volley.newRequestQueue(this);
// Instantiate the current List of geofences
mCurrentGeofences = new ArrayList<Geofence>();
mGeofencePendingIntent = null;
setUpLocationClientIfNeeded();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
mGoogleApiClient.connect();
Log.d(TAG,"onStartCommand: ");
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
/*
WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring.
This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find.
*/
if (this.mWakeLock == null) { //**Added this
this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
}
if (!this.mWakeLock.isHeld()) { //**Added this
this.mWakeLock.acquire();
}
if(!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress)
{
//appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
private void setUpLocationClientIfNeeded()
{
if(mGoogleApiClient == null)
googleApiClientBuild();
}
protected synchronized void googleApiClientBuild(){
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(120000); // Update location every 60 seconds
Log.d(TAG,"in onConnected: ");
if ( ContextCompat.checkSelfPermission( this, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions( mActivity, new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION },
REQUEST_CODE_LOCATION );
}else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
//Location mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
//txtOutput.setText(mLocation.toString());
Log.d(TAG, "calling fusedLocationApi");
}
continueAddGeofences();
}
#Override
public void onConnectionSuspended(int i) {
// Turn off the request flag
mInProgress = false;
// Destroy the current location client
mGoogleApiClient = null;
Log.d(TAG, "onConnectionSuspended ");
}
#Override
public void onLocationChanged(Location location) {
mLocation = location;
Log.d(TAG,"in onLocationChanged: ");
Log.d(TAG, mLocation.toString());
// save new location to db
connectToDb(); // checking for status 1
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
mInProgress = false;
Log.d(TAG, "onConnectionFailed");
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
Log.d(TAG, "google play services has solution");
// If no resolution is available, display an error dialog
} else {
Log.d(TAG, "no solution for connection failure");
}
}
#Override
public void onDestroy() {
// Turn off the request flag
this.mInProgress = false;
if (this.servicesAvailable && this.mGoogleApiClient != null) {
this.mGoogleApiClient.unregisterConnectionCallbacks(this);
this.mGoogleApiClient.unregisterConnectionFailedListener(this);
this.mGoogleApiClient.disconnect();
// Destroy the current location client
this.mGoogleApiClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ":
// Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
super.onDestroy();
}
public void connectToDb(){
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
Toast.makeText(getApplicationContext() , ""+s,Toast.LENGTH_LONG).show();
Log.d(TAG, ""+s);
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray jsonArray = jsonObject.getJSONArray("result");
if(jsonArray.length()!=0){
Log.d(TAG,"array length not 0");
JSONObject personInDanger = jsonArray.getJSONObject(0);
setGeofence(Double.valueOf(personInDanger.getString("latitude")), Double.valueOf(personInDanger.getString("longitude")));
}
}catch (JSONException je) {
// do something with it
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(), ""+volleyError, Toast.LENGTH_LONG).show();
}
});
requestQueue.add(stringRequest);
}
/**
* Verify that Google Play services is available before making a request.
*
* #return true if Google Play services is available, otherwise false
*/
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(GeofenceUtils.APPTAG, getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Toast.makeText(getApplicationContext(), "Google play services not available", Toast.LENGTH_SHORT).show();
//Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, (Activity) getApplicationContext(), 0);
//if (dialog != null) {
// ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// errorFragment.setDialog(dialog);
// errorFragment.show(getSupportFragmentManager(), GeofenceUtils.APPTAG);
}
return false;
}
public void setGeofence(Double latitude , Double longitude){
Log.d(TAG, "in setGeofence");
if (!servicesConnected()) {
return;
}
SimpleGeofence newGeofence = new SimpleGeofence(
"1",
// Get latitude, longitude, and radius from the db
latitude,
longitude,
Float.valueOf("50.0"),
// Set the expiration time
Geofence.NEVER_EXPIRE,
// Detect both entry and exit transitions
Geofence.GEOFENCE_TRANSITION_ENTER
);
mCurrentGeofences.add(newGeofence.toGeofence());
// Start the request. Fail if there's already a request in progress
try {
// Try to add geofences
addGeofences(mCurrentGeofences);
} catch (UnsupportedOperationException e) {
// Notify user that previous request hasn't finished.
Toast.makeText(this, R.string.add_geofences_already_requested_error,
Toast.LENGTH_LONG).show();
}
}
public void addGeofences(ArrayList<Geofence> geofences) throws UnsupportedOperationException {
if (!mInProgress) {
// Toggle the flag and continue
mInProgress = true;
// Request a connection to Location Services
requestConnection();
// If a request is in progress
} else {
// Throw an exception and stop the request
throw new UnsupportedOperationException();
}
}
private void requestConnection() {
getLocationClient().connect();
}
private GoogleApiClient getLocationClient() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
return mGoogleApiClient;
}
private void continueAddGeofences() {
// Get a PendingIntent that Location Services issues when a geofence transition occurs
mGeofencePendingIntent = createRequestPendingIntent();
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(mActivity, "not connected", Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
// The GeofenceRequest object.
mCurrentGeofences,
// A pending intent that that is reused when calling removeGeofences(). This
// pending intent is used to generate an intent when a matched geofence
// transition is observed.
mGeofencePendingIntent
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
logSecurityException(securityException);
}
}
private void logSecurityException(SecurityException securityException) {
Log.e(GeofenceUtils.APPTAG , "Invalid location permission. " +
"You need to use ACCESS_FINE_LOCATION with geofences", securityException);
}
public void onResult(Status status) {
Intent broadcastIntent = new Intent();
// Temp storage for messages
String msg;
if (status.isSuccess()) {
Toast.makeText(
mActivity, "Geofences added",
Toast.LENGTH_SHORT
).show();
msg = mActivity.getString(R.string.add_geofences_result_success, status);
// In debug mode, log the result
Log.d(GeofenceUtils.APPTAG, msg);
// Create an Intent to broadcast to the app
broadcastIntent.setAction(GeofenceUtils.ACTION_GEOFENCES_ADDED)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, msg);
// If adding the geofences failed
} else {
/*
* Create a message containing the error code and the list
* of geofence IDs you tried to add
*/
msg = mActivity.getString(
R.string.add_geofences_result_failure,
status.getStatusCode(), status.getStatusMessage());
// Log an error
Log.e(GeofenceUtils.APPTAG, msg);
}
}
private PendingIntent createRequestPendingIntent() {
// If the PendingIntent already exists
if (null != mGeofencePendingIntent) {
// Return the existing intent
return mGeofencePendingIntent;
// If no PendingIntent exists
} else {
Intent intent = new Intent("com.example.android.geofence.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(
mActivity,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
}
}
My logs:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:506)
at android.app.PendingIntent.getBroadcast(PendingIntent.java:495)
at com.example.android.safetyalert.GPSPollingService.createRequestPendingIntent(GPSPollingService.java:449)
at com.example.android.safetyalert.GPSPollingService.continueAddGeofences(GPSPollingService.java:369)
at com.example.android.safetyalert.GPSPollingService.onConnected(GPSPollingService.java:163)
at com.google.android.gms.common.internal.zzl.zzm(Unknown Source)
at com.google.android.gms.internal.zzof.zzk(Unknown Source)
at com.google.android.gms.internal.zzod.zzsb(Unknown Source)
at com.google.android.gms.internal.zzod.onConnected(Unknown Source)
at com.google.android.gms.internal.zzoh.onConnected(Unknown Source)
at com.google.android.gms.internal.zznw.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzk$1.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzd$zzj.zztp(Unknown Source)
at com.google.android.gms.common.internal.zzd$zza.zzc(Unknown Source)
at com.google.android.gms.common.internal.zzd$zza.zzw(Unknown Source)
at com.google.android.gms.common.internal.zzd$zze.zztr(Unknown Source)
at com.google.android.gms.common.internal.zzd$zzd.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
I have tried everything I could think of.
I'm polling the GPS in order to provide accurate location to the OS to increase the accuracy of geofencing. I know it will drain my battery but for now that's not a problem.
Service already has Context. You shouldn't use Context from the Activity because if your Activity is killed mActivity will be null causing all sort of issues. Replace else block in createRequestPendingIntent with this
} else {
Intent intent = new Intent("com.example.android.geofence.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}

GoogleFit wasn't able to connect, so the request failed-Android

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();
}
}
}
}

How to Use com.google.android.gms.common.api.GoogleApiClient, not the ActivityRecognitionClient, to request ActivityUpdates in android?

The motto here is calling the Service 'ActivityTrackerService' when I say requestActivityUpdates() using the GoogleApiClient's ActivityRecognition.ActivityRecognitionApi as shown in the code below when googleApiClient.connect() is called. After the api is connected the onConnected callback executes and activity updates are requested. The code runs perfectly fine as in the result call back i get a success. But some how Service class onHandleIntent is not called. I am not sure if the service has started working or not.
Service Provider Class:
public class ActivityServiceProvider {
private Context context;
private GoogleApiClient googleApiClient;
private PendingIntent mActivityRecognitionPendingIntent;
public ActivityServiceProvider(Context context) {
this.context = context;
createGoogleLocationServiceClient();
}
private void createGoogleLocationServiceClient() {
googleApiClient = new GoogleApiClient.Builder(context).addApi(ActivityRecognition.API)
.addConnectionCallbacks(new ConnectionCallbacks() {
#Override
public void onConnectionSuspended(int arg0) {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient Suspended");
}
#Override
public void onConnected(Bundle arg0) {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient Connected Now");
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(googleApiClient,
ActivityUtils.DETECTION_INTERVAL_MILLISECONDS, getPendingIntent()).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status arg0) {
if (arg0.isSuccess()) {
Log.d(ActivityUtils.APPTAG, "Updates Requested Successfully");
} else {
Log.d(ActivityUtils.APPTAG, "Updates could not be requested");
}
}
});
}
}).addOnConnectionFailedListener(new OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult arg0) {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient Connection Failed");
}
}).build();
}
public PendingIntent getRequestPendingIntent() {
return mActivityRecognitionPendingIntent;
}
public void setRequestPendingIntent(PendingIntent intent) {
mActivityRecognitionPendingIntent = intent;
}
private PendingIntent getPendingIntent() {
Intent intent = new Intent(context, ActivityTrackerService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
setRequestPendingIntent(pendingIntent);
return pendingIntent;
}
private boolean servicesConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (ConnectionResult.SUCCESS == resultCode) {
Log.d(ActivityUtils.APPTAG, context.getString(R.string.play_services_available));
return true;
} else {
Log.d(ActivityUtils.APPTAG, context.getString(R.string.play_services_unavailable));
return false;
}
}
public void connect() {
if (servicesConnected() && !googleApiClient.isConnected()) {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient Connection Initiated: connect() Called");
googleApiClient.connect();
} else {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient already connected or is unavailable");
}
}
public void disconnect() {
if (servicesConnected() && googleApiClient.isConnected()) {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient disconnection kicked");
if (mActivityRecognitionPendingIntent != null && googleApiClient != null) {
ActivityRecognition.ActivityRecognitionApi.removeActivityUpdates(googleApiClient,
mActivityRecognitionPendingIntent);
}
googleApiClient.disconnect();
} else {
Log.d(ActivityUtils.APPTAG, "GoogleApiClient already disconnected or is unavailable");
}
}
}
Service Class:
public class ActivityTrackerService extends IntentService {
private SharedPreferences mPrefs;
public ActivityTrackerService() {
super("ActivityTrackerService");
}
#Override
protected void onHandleIntent(Intent intent) {
mPrefs = getApplicationContext().getSharedPreferences(ActivityUtils.SHARED_PREFERENCES, Context.MODE_PRIVATE);
if (ActivityRecognitionResult.hasResult(intent)) {
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
DetectedActivity mostProbableActivity = result.getMostProbableActivity();
int confidence = mostProbableActivity.getConfidence();
int activityType = mostProbableActivity.getType();
String activityName = ActivityUtils.getNameFromType(activityType);
Log.d(ActivityUtils.APPTAG, "Activity Detected:" + activityName);
Intent regularActivityUpdateIntent = new Intent(ActivityUtils.REGULAR_ACTIVITY_UPDATE_INTENT);
regularActivityUpdateIntent.putExtra(ActivityUtils.EXTRA_ACTIVITY_NAME, activityName);
regularActivityUpdateIntent.putExtra(ActivityUtils.EXTRA_ACTIVITY_TYPE, activityType);
getApplicationContext().sendBroadcast(regularActivityUpdateIntent);
if (!mPrefs.contains(ActivityUtils.KEY_PREVIOUS_ACTIVITY_TYPE)) {
Editor editor = mPrefs.edit();
editor.putInt(ActivityUtils.KEY_PREVIOUS_ACTIVITY_TYPE, activityType);
editor.putString(ActivityUtils.KEY_PREVIOUS_ACTIVITY_NAME, activityName);
editor.commit();
Intent newActivityUpdateIntent = new Intent(ActivityUtils.NEW_ACTIVITY_UPDATE_INTENT);
regularActivityUpdateIntent.putExtra(ActivityUtils.EXTRA_ACTIVITY_NAME, activityName);
regularActivityUpdateIntent.putExtra(ActivityUtils.EXTRA_ACTIVITY_TYPE, activityType);
getApplicationContext().sendBroadcast(newActivityUpdateIntent);
} else if (isMoving(activityType) && activityChanged(activityType) && (confidence >= 50)) {
sendNotification();
}
}
}
private void sendNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
builder.setContentTitle("Attention").setContentText("Click to turn on GPS, or swipe to ignore")
.setSmallIcon(R.drawable.ic_notification).setContentIntent(getContentIntent());
NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifyManager.notify(0, builder.build());
}
private PendingIntent getContentIntent() {
Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
return PendingIntent.getActivity(getApplicationContext(), 0, gpsIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private boolean activityChanged(int currentType) {
int previousType = mPrefs.getInt(ActivityUtils.KEY_PREVIOUS_ACTIVITY_TYPE, DetectedActivity.UNKNOWN);
if (previousType != currentType) {
return true;
} else {
return false;
}
}
private boolean isMoving(int type) {
switch (type) {
case DetectedActivity.STILL:
case DetectedActivity.TILTING:
case DetectedActivity.UNKNOWN:
return false;
default:
return true;
}
}
}
The specific android manifest entries are as follows :
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<service android:name=".ActivityTrackerService" >
</service>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
Has anybody tried using the com.google.android.gms.common.api.GoogleApiClient to request for ActivityUpdates using ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates or Is there some othe rway to use GoogleApiClient to request activity updates ??
I had the same problem, and even with explicit intent the onHandleIntent() would not be called.
I found that onStartCommand was called however, and could get around it by setting and checking the intent action.
It is not an explanation or solutions per se, but at least a workaound ;)
you should write your project's gradle (app)
dependencies{
compile 'com.google.firebase:firebase-appindexing:11.8.0'
....
}
then add libraries and import.

Android LocationServices.GeofencingApi example usage

Does anyone know of an example of using the LocationServices.GeofencingApi?
All the android geofencing examples I find are using the deprecated LocationClient class.
From what I can see, the LocationServices class is the one to use, but there doesn't seem to be any working examples on how to use it.
The closest I've found is this post highlighting location update requests
UPDATE: The closest answer I've found is this git example project - but it still uses the deprecated LocationClient to get triggered fences.
I just migrated my code to the new API. Here is a working example:
A working project on GitHub based on this answer: https://github.com/androidfu/GeofenceExample
This helper class registers the geofences using the API. I use a callback interface to communicate with the calling activity/fragment. You can build a callback that fits your needs.
public class GeofencingRegisterer implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private List<Geofence> geofencesToAdd;
private PendingIntent mGeofencePendingIntent;
private GeofencingRegistererCallbacks mCallback;
public final String TAG = this.getClass().getName();
public GeofencingRegisterer(Context context){
mContext =context;
}
public void setGeofencingCallback(GeofencingRegistererCallbacks callback){
mCallback = callback;
}
public void registerGeofences(List<Geofence> geofences){
geofencesToAdd = geofences;
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
if(mCallback != null){
mCallback.onApiClientConnected();
}
mGeofencePendingIntent = createRequestPendingIntent();
PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, geofencesToAdd, mGeofencePendingIntent);
result.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
// Successfully registered
if(mCallback != null){
mCallback.onGeofencesRegisteredSuccessful();
}
} else if (status.hasResolution()) {
// Google provides a way to fix the issue
/*
status.startResolutionForResult(
mContext, // your current activity used to receive the result
RESULT_CODE); // the result code you'll look for in your
// onActivityResult method to retry registering
*/
} else {
// No recovery. Weep softly or inform the user.
Log.e(TAG, "Registering failed: " + status.getStatusMessage());
}
}
});
}
#Override
public void onConnectionSuspended(int i) {
if(mCallback != null){
mCallback.onApiClientSuspended();
}
Log.e(TAG, "onConnectionSuspended: " + i);
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if(mCallback != null){
mCallback.onApiClientConnectionFailed(connectionResult);
}
Log.e(TAG, "onConnectionFailed: " + connectionResult.getErrorCode());
}
/**
* Returns the current PendingIntent to the caller.
*
* #return The PendingIntent used to create the current set of geofences
*/
public PendingIntent getRequestPendingIntent() {
return createRequestPendingIntent();
}
/**
* Get a PendingIntent to send with the request to add Geofences. Location
* Services issues the Intent inside this PendingIntent whenever a geofence
* transition occurs for the current list of geofences.
*
* #return A PendingIntent for the IntentService that handles geofence
* transitions.
*/
private PendingIntent createRequestPendingIntent() {
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
} else {
Intent intent = new Intent(mContext, GeofencingReceiver.class);
return PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
}
This class is the base class for your geofence transition receiver.
public abstract class ReceiveGeofenceTransitionIntentService extends IntentService {
/**
* Sets an identifier for this class' background thread
*/
public ReceiveGeofenceTransitionIntentService() {
super("ReceiveGeofenceTransitionIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
if(event != null){
if(event.hasError()){
onError(event.getErrorCode());
} else {
int transition = event.getGeofenceTransition();
if(transition == Geofence.GEOFENCE_TRANSITION_ENTER || transition == Geofence.GEOFENCE_TRANSITION_DWELL || transition == Geofence.GEOFENCE_TRANSITION_EXIT){
String[] geofenceIds = new String[event.getTriggeringGeofences().size()];
for (int index = 0; index < event.getTriggeringGeofences().size(); index++) {
geofenceIds[index] = event.getTriggeringGeofences().get(index).getRequestId();
}
if (transition == Geofence.GEOFENCE_TRANSITION_ENTER || transition == Geofence.GEOFENCE_TRANSITION_DWELL) {
onEnteredGeofences(geofenceIds);
} else if (transition == Geofence.GEOFENCE_TRANSITION_EXIT) {
onExitedGeofences(geofenceIds);
}
}
}
}
}
protected abstract void onEnteredGeofences(String[] geofenceIds);
protected abstract void onExitedGeofences(String[] geofenceIds);
protected abstract void onError(int errorCode);
}
This class implements the abstract class and does all the handling of geofence transitions
public class GeofencingReceiver extends ReceiveGeofenceTransitionIntentService {
#Override
protected void onEnteredGeofences(String[] geofenceIds) {
Log.d(GeofencingReceiver.class.getName(), "onEnter");
}
#Override
protected void onExitedGeofences(String[] geofenceIds) {
Log.d(GeofencingReceiver.class.getName(), "onExit");
}
#Override
protected void onError(int errorCode) {
Log.e(GeofencingReceiver.class.getName(), "Error: " + i);
}
}
And in your manifest add:
<service
android:name="**xxxxxxx**.GeofencingReceiver"
android:exported="true"
android:label="#string/app_name" >
</service>
Callback Interface
public interface GeofencingRegistererCallbacks {
public void onApiClientConnected();
public void onApiClientSuspended();
public void onApiClientConnectionFailed(ConnectionResult connectionResult);
public void onGeofencesRegisteredSuccessful();
}

Categories

Resources