FusedLocationApi with PendingIntent for background location updates. Unable to receive updates
Asked Answered
S

1

8

The sample source code from google was to easy to implement continuous location updates on frontend, but I still can;t get or understand clearly how the background location updates work using FusedLocationApi and PendingIntent.

LocationService class:

public class LocationService extends IntentService {
private static final String TAG = LocationService.class.getSimpleName();

private static final String ACTION_LOCATION_UPDATED = "location_updated";
private static final String ACTION_REQUEST_LOCATION = "request_location";

public static IntentFilter getLocationUpdatedIntentFilter() {
    return new IntentFilter(LocationService.ACTION_LOCATION_UPDATED);
}

public static void requestLocation(Context context) {
    Intent intent = new Intent(context, LocationService.class);
    intent.setAction(LocationService.ACTION_REQUEST_LOCATION);
    context.startService(intent);
}

public LocationService() {
    super(TAG);
}

@Override
protected void onHandleIntent(Intent intent) {
    String action = intent != null ? intent.getAction() : null;
    if (ACTION_REQUEST_LOCATION.equals(action)) {
        onRequestLocation();
    }
    else if(ACTION_LOCATION_UPDATED.equals(action)) {
        onLocationUpdated(intent);
    }
}

/**
 * Called when a location update is requested. We block until we get a result back.
 * We are using Fused Location Api.
 */
private void onRequestLocation() {
    Log.v(TAG, ACTION_REQUEST_LOCATION);
    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(LocationServices.API)
            .build();

    // we block here
    ConnectionResult connectionResult = googleApiClient.blockingConnect(10, TimeUnit.SECONDS);

    if (connectionResult.isSuccess() && googleApiClient.isConnected()) {

        Intent locationUpdatedIntent = new Intent(this, LocationService.class);
        locationUpdatedIntent.setAction(ACTION_LOCATION_UPDATED);

        // Send last known location out first if available
        Location location = FusedLocationApi.getLastLocation(googleApiClient);
        if (location != null) {
            Intent lastLocationIntent = new Intent(locationUpdatedIntent);
            lastLocationIntent.putExtra(
                    FusedLocationProviderApi.KEY_LOCATION_CHANGED, location);
            startService(lastLocationIntent);
        }

        // Request new location
        LocationRequest mLocationRequest = new LocationRequest()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        FusedLocationApi.requestLocationUpdates(
                googleApiClient, mLocationRequest,
                PendingIntent.getService(this, 0, locationUpdatedIntent, 0));

        googleApiClient.disconnect();
    } else {
        Log.e(TAG, String.format("Failed to connect to GoogleApiClient (error code = %d)",
                connectionResult.getErrorCode()));
    }
}

/**
 * Called when the location has been updated & broadcast the new location
 */
private void onLocationUpdated(Intent intent) {
    Log.v(TAG, ACTION_LOCATION_UPDATED);

    // Extra new location
    Location location =
            intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);

    if (location != null) {
        LatLng latLngLocation = new LatLng(location.getLatitude(), location.getLongitude());
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
 }
}

MainActivity The code looks messy so I will share the code in a drive link: https://drive.google.com/open?id=0B7QMYFlbkUpOVjkxMUtfenRLXzA

However, I have followed the example from https://gist.githubusercontent.com/allenchi/c9659369c306752c0047/raw/16d6cd8e311013379e55b496d2b6d13347f418d6/gistfile1.txt

The following part in the example is what I just cannot understand placement in MainActivity. How do I receive location updates using Broadcast receiver? I would also require a clean understanding of FusedLocation running in background and how I can utilize to get an on the fly gps tracker implemented.

@Override
protected void onResume() {
    super.onResume();
    if(checkPlayServices()) {
        LocationService.requestLocation(this);
        LocalBroadcastManager.getInstance(getActivity())
                   .registerReceiver(locationReceiver, LocationService.getLocationUpdatedIntentFilter());
    }
}

@Override
public void onResume() {
    super.onResume();
    LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
    locationReceiver, LocationService.getLocationUpdatedIntentFilter());
}

@Override
public void onPause() {
    super.onPause();
    LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(locationReceiver);
}

private BroadcastReceiver locationReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Location location = intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
        if (location != null) {
          LatLng latestLocation = new LatLng(location.getLatitude(), location.getLongitude());
          // do something with the location
        }
    }
};
Swoop answered 16/11, 2015 at 12:35 Comment(0)
O
5

In the sample below you can receive the location updates when the app runs in the background every 5 seconds using the PRIORITY_HIGH_ACCURACY mode. You will see these updates by receiving notifications indicating your location's coordinates.

I also wanted to test whether the updates can be received after the app has been killed by the system as it is stated here:

public abstract PendingResult requestLocationUpdates (GoogleApiClient client, LocationRequest request, PendingIntent callbackIntent)

This method is suited for the background use cases, more specifically for receiving location updates, even when the app has been killed by the system. In order to do so, use a PendingIntent for a started service.

that's why I have called the System.exit(0) in the onBackPressed() method of the Activity, which you can of course omit.

The Service:

public class LocationService extends IntentService{

private static final String INTENT_SERVICE_NAME = LocationService.class.getName();

public LocationService() {
    super(INTENT_SERVICE_NAME);
}

@Override
protected void onHandleIntent(Intent intent) {
    if (null == intent) {
        return;
    }

    Bundle bundle = intent.getExtras();

    if (null == bundle) {
        return;
    }

    Location location = bundle.getParcelable("com.google.android.location.LOCATION");

    if (null == location) {
        return;
    }

    if (null != location) {
        // TODO: Handle the incoming location

        Log.i(INTENT_SERVICE_NAME, "onHandleIntent " + location.getLatitude() + ", " + location.getLongitude());

        // Just show a notification with the location's coordinates
        NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder notification = new NotificationCompat.Builder(this);
        notification.setContentTitle("Location");
        notification.setContentText(location.getLatitude() + ", " + location.getLongitude());
        notification.setSmallIcon(R.drawable.ic_audiotrack);
        notificationManager.notify(1234, notification.build());
    }
}

}

The Activity:

public class MainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener{

private GoogleApiClient googleApiClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

}

@Override
public void onStart() {
    super.onStart();
    googleApiClient.connect();
}

@Override
public void onStop() {
    super.onStop();
    if (googleApiClient.isConnected()) {
        googleApiClient.disconnect();
    }
}

@Override
public void onBackPressed() {
    // Check whether you receive location updates after the app has been killed by the system
    System.exit(0);
}

@Override
public void onConnected(Bundle bundle) {
    requestLocationUpdates();
}

@Override
public void onConnectionSuspended(int cause) {
    googleApiClient.connect();
}

@Override
public void onConnectionFailed(ConnectionResult result) {

}

public void requestLocationUpdates() {
    LocationRequest locationRequest = new LocationRequest()
            .setInterval(5 * 1000)
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    Intent intent = new Intent(this, LocationService.class);
    PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, pendingIntent);
}

}

The permission in the manifest:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Octosyllable answered 25/11, 2016 at 14:12 Comment(2)
the intent service should be declared in manifest file too : <service android:name=".Service.LocationService" android:exported="false" />Disencumber
This retrieves locations from the Activity on the Foreground. User asked to retrieve it in backgroundGastronome

© 2022 - 2024 — McMap. All rights reserved.