Awareness API delays activity callbacks significantly

551 Views Asked by At

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?

1

There are 1 best solutions below

0
On

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.