user1871869
user1871869

Reputation: 3367

Waiting until location is on after turning it on through location services alert

I am having a problem where if my phone's location services is turned off, I want to set an alert to open the location services settings and turn it on there. This works fine but the issue is when I navigate back to my application after turning it on. It seems like when I click back, the onResume of my activity is called but the location is still not set correctly there until onResume is completed. Here is my code:

Comments.java:

@Override
public void onResume() {
    super.onResume();
    locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
    Location location = LocationService.getLastLocation();
    if(location == null) {
        if(getLastKnownLocation() == null) {
            if(checkLocationEnabled()); {
                location = getLastKnownLocation();
            }
        }
    }

    if(location != null) {
        progressOverlay = fragmentView.findViewById(R.id.progress_overlay);
        AndroidUtils.animateView(progressOverlay, View.VISIBLE, 0.9f, 200);
        //Within this function call, the progress overlay is set to View.GONE.
        databaseQuery.getPublicPosts(location, progressOverlay, fragmentView, getContext());
    } else {
        //We need to handle an error saying that location is not enabled for this device and exit them out of the app
    }
}

private Location getLastKnownLocation() {
    locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
    List<String> providers = locationManager.getProviders(true);
    Location bestLocation = null;
    for (String provider : providers) {
        if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            return null;
        } else {
            Location l = locationManager.getLastKnownLocation(provider);
            if (bestLocation == null || l.getAccuracy() < bestLocation.getAccuracy()) {
                // Found best last known location: %s", l);
                bestLocation = l;
            }
        }
    }

    return bestLocation;
}

public boolean checkLocationEnabled() {
    try {
        gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch(Exception ex) {
    }
    try {
        network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    } catch(Exception ex) {

    }
    if(!gps_enabled && !network_enabled) {
        // notify user
        AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
        dialog.setMessage(getContext().getResources().getString(R.string.gpsNetworkNotEnabled));
        dialog.setPositiveButton(getContext().getResources().getString(R.string.openLocationSettings), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                getContext().startActivity(myIntent);
                //get gps
            }
        });
        dialog.setNegativeButton(getContext().getString(R.string.cancel), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface paramDialogInterface, int paramInt) {

            }
        });
        dialog.show();
    }
    return gps_enabled || network_enabled;
}

What I do is when the phone location services is off, I set up an alert that takes you to the location services screen. When the user turns on the location services screen, if he or she clicks "back" on his or her phone, they should be taken back to the initial screen that showed that their location services was off alert. However, when navigating back to that screen, my progressOverlay variable is still visible because the progressOverlay is set to View.GONE when the databaseQuery.getPublicPosts call goes through. That doesn't seem to happen because the if(location != null) statement is probably false right when we navigate back to the screen, but is probably set to true after the phone waits a few seconds and fully obtains the phone's location. It's interesting because if I put a debugger anywhere in that code, the location services will be set correctly and my progressOverlay will go away because the location gets set while I am debugging the code. Is there any way I can "wait" or continue to show the loading screen until the location services is fully on before calling databaseQuery.getPublicPosts? Any help would be appreciated.

Upvotes: 4

Views: 2060

Answers (3)

Saveen
Saveen

Reputation: 4220

hi why trying to use getLastKnownLocation.It return your previous latitude and longitude and it might take some time to update lastknown location. Most probably it retrun you null after on your location.

I'm just referring you google Fused api for location any kind of updation or current.Its very accurate.

How you can fused api in your project.See i'll give you small example.

Step 1. Make this class GoogleLocationService.java

public class GoogleLocationService {
private GoogleServicesCallbacks callbacks = new GoogleServicesCallbacks();
LocationUpdateListener locationUpdateListener;
Context activity;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;

public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000;


public GoogleLocationService(Context activity, LocationUpdateListener locationUpdateListener) {
    this.locationUpdateListener = locationUpdateListener;
    this.activity = activity;
    buildGoogleApiClient();
}

protected synchronized void buildGoogleApiClient() {
    //Log.i(TAG, "Building GoogleApiClient");
    mGoogleApiClient = new GoogleApiClient.Builder(activity)
            .addConnectionCallbacks(callbacks)
            .addOnConnectionFailedListener(callbacks)
            .addApi(LocationServices.API)
            .build();
    createLocationRequest();
    mGoogleApiClient.connect();
}

protected void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

}

private class GoogleServicesCallbacks implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

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

    @Override
    public void onConnectionSuspended(int i) {
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

        if (connectionResult.getErrorCode() == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) {
            Toast.makeText(activity, "Google play service not updated", Toast.LENGTH_LONG).show();

        }
        locationUpdateListener.cannotReceiveLocationUpdates();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location.hasAccuracy()) {
            if (location.getAccuracy() < 30) {
                locationUpdateListener.updateLocation(location);
            }
        }
    }
}

private static boolean locationEnabled(Context context) {
    boolean gps_enabled = false;
    LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    try {
        gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return gps_enabled;
}

private boolean servicesConnected(Context context) {
    return isPackageInstalled(GooglePlayServicesUtil.GOOGLE_PLAY_STORE_PACKAGE, context);
}

private boolean isPackageInstalled(String packagename, Context context) {
    PackageManager pm = context.getPackageManager();
    try {
        pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
        return true;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
        return false;
    }
}


public void startUpdates() {
    /*
     * Connect the client. Don't re-start any requests here; instead, wait
     * for onResume()
     */
    if (servicesConnected(activity)) {
        if (locationEnabled(activity)) {
            locationUpdateListener.canReceiveLocationUpdates();
            startLocationUpdates();
        } else {
            locationUpdateListener.cannotReceiveLocationUpdates();
            Toast.makeText(activity, "Unable to get your location.Please turn on your device Gps", Toast.LENGTH_LONG).show();
        }
    } else {
        locationUpdateListener.cannotReceiveLocationUpdates();
        Toast.makeText(activity, "Google play service not available", Toast.LENGTH_LONG).show();
    }
}

//stop location updates
public void stopUpdates() {
    stopLocationUpdates();
}

//start location updates
private void startLocationUpdates() {

    if (checkSelfPermission(activity, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(activity, ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, callbacks);
    }
}

public void stopLocationUpdates() {
    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, callbacks);
    }
}

public void startGoogleApi() {
    mGoogleApiClient.connect();
}

public void closeGoogleApi() {
    mGoogleApiClient.disconnect();
}

 }

Step2. Make this interface LocationUpdateListener.java

 public interface LocationUpdateListener {

/**
 * Called immediately the service starts if the service can obtain location
 */
void canReceiveLocationUpdates();

/**
 * Called immediately the service tries to start if it cannot obtain location - eg the user has disabled wireless and
 */
void cannotReceiveLocationUpdates();

/**
 * Called whenever the location has changed (at least non-trivially)
 * @param location
 */
void updateLocation(Location location);

/**
 * Called when GoogleLocationServices detects that the device has moved to a new location.
 * @param localityName The name of the locality (somewhere below street but above area).
 */
void updateLocationName(String localityName, Location location);
}

Step 3. Use this piece of code where you want to get location

public class MainActivity extends ActionBarActivity {

private GoogleLocationService googleLocationService;

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

    googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() {
    @Override
    public void canReceiveLocationUpdates() {
    }

    @Override
    public void cannotReceiveLocationUpdates() {
    }

    //update location to our servers for tracking purpose
    @Override
    public void updateLocation(Location location) {
        if (location != null ) {
            Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude());

        }
    }

    @Override
    public void updateLocationName(String localityName, Location location) {

        googleLocationService.stopLocationUpdates();
    }
});
googleLocationService.startUpdates();


}

@Override
public void onDestroy() {
    super.onDestroy();
if (googleLocationService != null) {
    googleLocationService.stopLocationUpdates();
}

}
}

Updated answer how to send and receive lat lng through broadcast

call this onlocationchanged

Intent sendBroadIntentPND = new Intent("COORD_BROADCAST_FILTER");
                    sendBroadIntentPND.putExtra("LOC_LAT", location.getLatitude());
sendBroadIntentPND.putExtra("LOC_LON", location.getLongitude());
getApplicationContext().sendBroadcast(sendBroadIntentPND);

then where you want to receive the location call this way

// declear global variable
private final String COORD_BROADCAST_FILTER = "COORD_BROADCAST_FILTER";
private Location newLocation;

private BroadcastReceiver coordinateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
try {
            newLocation.setLatitude(intent.getDoubleExtra("LOC_LAT", 0.0));
            newLocation.setLongitude(intent.getDoubleExtra("LOC_LON", 0.0));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

 };

Register you receiver oncreate,

 getActivity().registerReceiver(coordinateReceiver, new IntentFilter(COORD_BROADCAST_FILTER));

unregister your receiver ondestroy

 getActivity().unregisterReceiver(coordinateReceiver);

Thanks hope this help you.

Upvotes: 1

user1506104
user1506104

Reputation: 7106

Please take note that

The Google Play services location APIs are preferred over the Android framework location APIs (android.location) as a way of adding location awareness to your app. If you are currently using the Android framework location APIs, you are strongly encouraged to switch to the Google Play services location APIs as soon as possible.

Upvotes: 0

M A
M A

Reputation: 72874

First you have an unwanted semi-colon in if(checkLocationEnabled()); which acts as an empty statement causing the second call to getLastKnownLocation() to always execute (this will most probably not affect the problem).

The LocationManager class has a constant KEY_STATUS_CHANGED that is the key of a bundle extra that is passed when a status change is broadcast. See the documentation related to the constant. To trigger this change you need to call [LocationManager.requestLocationUpdates](https://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent)) so that the location manager receives such a status update.

From the documentation of this method, you can either use a BroadcastReceiver to receive the update by filtering on the above constant. Here is a related post that does this. Or you can use another overloaded version of the request updates method that takes a LocationListener which has an onStatusChanged callback.

A similar update exists when a location provider is enabled, with the KEY_PROVIDER_ENABLED. You can try listening for both updates if the status update didn't work.

Note that when requesting location updates for providers, in order to include updates for all providers including disabled ones, you should retrieve them using LocationManager.getProviders(false).

Once you receive the appropriate update events, you can call removeUpdates to remove the update requests.

Upvotes: 1

Related Questions