9

When I enter a screen, I check for if GPS is turned on, if not, the dialog to enable GPS is shown. When user clicks Yes, onActivityResult -> GPS is turned on and I try to get the location but this always returns null

When I enter the screen with GPS already on, location is retrieved properly. I have been struggling with this for few days now and can't seem to find any resources.

UserLocationUtilities.java

public class UserLocationUtilities implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener{

    GoogleApiClient googleApiClient;
    Activity activity;
    protected static final int REQUEST_CHECK_SETTINGS = 0x1;

    boolean isGPSEnabled = false;
    // flag for network status
    boolean isNetworkEnabled = false;
    // flag for GPS status
    boolean canGetLocation = false;

    protected LocationManager locationManager;
    protected LocationListener locationListener;
    protected Location location;
    protected double latitude,longitude;
    protected boolean gps_enabled,network_enabled;

    // The minimum distance to change Updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
    // The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 1 * 1000 * 60; // 1 minute

    public UserLocationUtilities(Activity activity){
        this.activity = activity;
    }

    public void settingsRequest()
    {
        if(googleApiClient == null){
            googleApiClient = new GoogleApiClient.Builder(activity)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this).build();
            googleApiClient.connect();
        }

        LocationRequest locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(30 * 1000);
        locationRequest.setFastestInterval(5 * 1000);
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest);
        builder.setAlwaysShow(true); //this is the key ingredient

        PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
        result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
            @Override
            public void onResult(LocationSettingsResult result) {
                final Status status = result.getStatus();
                final LocationSettingsStates state = result.getLocationSettingsStates();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.SUCCESS:
                        // All location settings are satisfied. The client can initialize location
                        // requests here.

                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        // Location settings are not satisfied. But could be fixed by showing the user
                        // a dialog.
                        try {
                            // Show the dialog by calling startResolutionForResult(),
                            // and check the result in onActivityResult().
                            status.startResolutionForResult(activity, REQUEST_CHECK_SETTINGS);
                        } catch (IntentSender.SendIntentException e) {
                            // Ignore the error.
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        // Location settings are not satisfied. However, we have no way to fix the
                        // settings so we won't show the dialog.
                        break;
                }
            }
        });
    }

    public Location getLocation() {
        if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            try {
                locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);

                isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

                if (!isGPSEnabled && !isNetworkEnabled) {
                    // no network provider is enabled
                } else {
                    this.canGetLocation = true;
                    if (isNetworkEnabled) {
                        locationManager.requestLocationUpdates(
                                LocationManager.NETWORK_PROVIDER,
                                MIN_TIME_BW_UPDATES,
                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        Log.d("Network", "Network");
                        if (locationManager != null) {
                            location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                            if (location != null) {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                    // if GPS Enabled get lat/long using GPS Services
                    if (isGPSEnabled) {
                        if (location == null) {
                            locationManager.requestLocationUpdates(
                                    LocationManager.GPS_PROVIDER,
                                    MIN_TIME_BW_UPDATES,
                                    MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                            Log.d("GPS Enabled", "GPS Enabled");
                            if (locationManager != null) {
                                location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                                if (location != null) {
                                    latitude = location.getLatitude();
                                    longitude = location.getLongitude();
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return location;
    }

    public boolean isLocationEnabled() {
        int locationMode = 0;
        String locationProviders;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            try {
                locationMode = Settings.Secure.getInt(activity.getApplicationContext().getContentResolver(), Settings.Secure.LOCATION_MODE);

            } catch (Settings.SettingNotFoundException e) {
                e.printStackTrace();
            }

            return locationMode != Settings.Secure.LOCATION_MODE_OFF;

        }else{
            locationProviders = Settings.Secure.getString(activity.getApplicationContext().getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
            return !TextUtils.isEmpty(locationProviders);
        }


    }

    @Override
    public void onConnected(Bundle bundle) {


    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

    @Override
    public void onLocationChanged(Location location) {

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
}

After user selects Yes in Settings Dialog, onActivityResult, I do location = userlocationutilities.getLocation(); and always returns null. If switch screens and come back, location is retrieved.

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
            case REQUEST_CHECK_SETTINGS:
                switch (resultCode) {
                    case Activity.RESULT_OK: //location settings dialog, user selected YES to enabling location

                        location = userLocationUtilities.getLocation();
                        if(location != null){
                            //location of user FOUND
                            Toast.makeText(getActivity(), "Lat: "+location.getLatitude()+" Long: "+location.getLongitude(), Toast.LENGTH_LONG).show();
                            getRingsNearMeCall();

                        }else{
                            //location of user NOT FOUND
                            Toast.makeText(getActivity(), "null location", Toast.LENGTH_LONG).show();

                        }

                        break;
                    case Activity.RESULT_CANCELED: //location settings dialog, user selected NO to enabling location
                        userLocationUtilities.settingsRequest(); //ask user again with Location Settings Dialog
                        break;
                }
                break;
        }
    }

Editted: I make the requestPermission in the fragment, the permission is granted

if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(getActivity(), new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION },
                    PERMISSION_ACCESS_FINE_LOCATION);
        }else{
            checkLocationSettingsGetRings();
        }
Divya Jain
  • 393
  • 1
  • 6
  • 22
yellowmonkey
  • 197
  • 3
  • 11

3 Answers3

0

LocationSettingsRequest is used just make location settings adequate, for example you want receive more accurate (HIGH_ACCURACY) locations, then you need GPS is enabled. So in that case, LocationSettingsRequest prompts the dialog to allow api change settings.

After pressing OK, you can see that GPS is enabled. But it does not mean you are granted to make location request yet.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case REQUEST_CHECK_SETTINGS:
            switch (resultCode) {
                case Activity.RESULT_OK:
                // Here means required settings are adequate.
                // We can make location request.
                // But are we granted to use request location updates ?
                break;
            }
            break;
        }
    }
}

Thats okay, but you are checking the permission, but you did never make requestPermissions. This is the first possible reason of getting null.

public Location getLocation() {
    if (ContextCompat.checkSelfPermission(activity, 
        Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        ...
    }
    return location;
}

Even you are previously granted to make location request

  location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
  location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

getLastKnownLocation() method could return null, this is not unexpected behaviour. This is the second possible reason of getting null

You are making location request, but the global location variable is never assigned in onLocationChanged callback.

 @Override
public void onLocationChanged(Location location) {
    // global location variable is not assigned ?
    // getLocation() method will return null if getLastKnownLocation()
    // did not return null previously. 
}

This is third possible reason of getting null.

blackkara
  • 4,900
  • 4
  • 28
  • 58
  • i am making the permission request in my fragment, if not granted, prompt user for permission.. we can assume that the location permission is granted, because i am able to get the location at any other time in the app except immediately after enabling the gps setting and also because i can go into my app's info and see that location permission is granted – yellowmonkey Jun 01 '16 at 02:26
  • 2
    based on my research, it seems as that since it is looking for last known location by any other app, since no other app used it since enabling it, that is why it is returning null. i am just not sure on how to go about fixing this issue – yellowmonkey Jun 01 '16 at 02:29
  • 2
    Hi, @shiv.s. Have you find any solution yet? I got the same problem with it too. – K.Sopheak Sep 15 '16 at 08:59
0

Finally, I find a solution: I create a thread and wait for my location available.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case REQUEST_LOCATION:
            switch (resultCode){
                case Activity.RESULT_OK:
                    mHandler = new Handler();
                    runnable = new Runnable() {
                        @Override
                        public void run() {
                            mHandler.postDelayed(this,1000);
                            checkLocationAvailable();
                        }
                    };
                    mHandler.postDelayed(runnable,1000);
                    break;
                case Activity.RESULT_CANCELED:
                    break;
            }
    }
}

Create a function to stop the thread when my location available.

private void checkLocationAvailable(){
  if (mMap.getMyLocation() != null) {
  mHandler.removeCallbacks(runnable);
  // do stuff
  }
}

It is not a good solution, but hope it will help.

K.Sopheak
  • 22,904
  • 4
  • 33
  • 78
0

Add this override method for me its worked fine--

@Override public void onLocationChanged(Location location) { getLocation("onLocationChanged"); }

ShriKant A
  • 105
  • 5