Search code examples
androidandroid-location

android : location api asking for wifi


This is weird. I mean, I have strong network, and GPS is turned On, still it asks for Wifi !!

I'm using new Location Api with class FusedLocationProviderClient.

This is how I am checking if Location Settings are enabled or not:

private void checkIfLocationSettingsAreEnabled() {
    LocationRequest locationRequest = new LocationRequest();
    locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    locationRequest.setInterval(10000);
    locationRequest.setFastestInterval(5000);

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
    builder.addLocationRequest(locationRequest);
    builder.setAlwaysShow(true);

    SettingsClient client = LocationServices.getSettingsClient(context);
    Task<LocationSettingsResponse> locationSettingsResponseTask = client.checkLocationSettings(builder.build());
    locationSettingsResponseTask.addOnSuccessListener(locationSettingsResponse -> {
        getLastKnownLocation();
    });
    locationSettingsResponseTask.addOnFailureListener(e -> {
        if (e instanceof ResolvableApiException) {
            myLocationListener.onResolutionNeeded(e);
        } else {
            myLocationListener.onLocationFailure(e);
        }
    });
}

With the above code, I am able to get below image:

enter image description here

But then, after clicking OK, again I make call to checkIfSettingsAreEnabled() this shows another popup as below:

enter image description here

I wonder why enabling Wifi is mandatory, even if I am on desert safari, where there is no Wifi to connect to !!

Is there any way to Skip this Wifi option, and work as normal as Google Maps does ?

In fact, Google Maps uses priority PRIORITY_HIGH_ACCURACY and still once, the first settings dialog has been shown, it doesn't ask second time to turn on Wifi.


Solution

  • With the below solution, I am able to skip this Wifi Settings Dialog. This is not a perfect solution, but just a workaround till I find perfect solution.

    Problem was, even after clicking "Ok" on Settings Dialog, it returned result as Activity.RESULT_CANCELLED. Reason was, Wifi was still turned off. So, as a quick fix, made a check in result Activity.RESULT_CANCELLED, that if I could get Location by checking LocationSettingStates.

    You can use my MyLocationUtils.java and Base classes LocationActivity.java or LocationFragment.java. Happy Coding..!!

    for getting location

    MyLocationUtils.java:

    public class MyLocationUtils {
    
        public static final int REQUEST_CODE_LOCATION_SETTINGS = 123;
    
        private static final int INTERVAL_IN_MS = 10000;
        private static final int FASTEST_INTERVAL_IN_MS = 5000;
        private static final int MAX_WAIT_TIME_IN_MS = 5000;
        private static final int NUMBER_OF_UPDATES = 1;
    
        private final MyLocationListener myLocationListener;
        private final Context context;
        private FusedLocationProviderClient mFusedLocationProviderClient;
        private LocationCallback mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
    
                Location location = null;
                if (locationResult.getLocations().size() > 0) {
                    location = locationResult.getLocations().get(0);
                }
    
                myLocationListener.onLocationSuccess(location);
    
                stopContinuousLocation();
            }
        };
    
        public MyLocationUtils(Context context, MyLocationListener myLocationListener) {
            this.context = context;
            this.myLocationListener = myLocationListener;
    
            initializeFusedLocationProviderClient();
        }
    
        private boolean checkIfRequiredLocationSettingsAreEnabled(Context context) {
            LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
            return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        }
    
        private void initializeFusedLocationProviderClient() {
            mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context);
        }
    
        public void stopContinuousLocation() {
            mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);
        }
    
        public void getLocation() {
            checkIfLocationSettingsAreEnabled();
        }
    
        private void checkIfLocationSettingsAreEnabled() {
            if (checkIfRequiredLocationSettingsAreEnabled(context)) {
                getLastKnownLocation();
            } else {
                LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
                builder.addLocationRequest(getLocationRequest());
                builder.setAlwaysShow(true);
    
                SettingsClient client = LocationServices.getSettingsClient(context);
                Task<LocationSettingsResponse> locationSettingsResponseTask = client.checkLocationSettings(builder.build());
                locationSettingsResponseTask.addOnSuccessListener(locationSettingsResponse -> {
                    // All location settings are satisfied. The client can initialize
                    // location requests here.
                    // ...
                    getLastKnownLocation();
                });
                locationSettingsResponseTask.addOnFailureListener(e -> {
                    if (e instanceof ResolvableApiException) {
                        myLocationListener.onResolutionNeeded(e);
                    } else {
                        myLocationListener.onLocationFailure(e);
                    }
                });
            }
        }
    
        @SuppressLint("MissingPermission")
        private void getLastKnownLocation() {
            Task<Location> locationTask = mFusedLocationProviderClient.getLastLocation();
            locationTask.addOnSuccessListener(location -> {
                // Got last known location. In some rare situations this can be null.
                if (location != null) {
                    myLocationListener.onLocationSuccess(location);
                } else {
                    startContinuousLocation();
                }
            });
            locationTask.addOnFailureListener(myLocationListener::onLocationFailure);
        }
    
        @SuppressLint("MissingPermission")
        private void startContinuousLocation() {
            mFusedLocationProviderClient.requestLocationUpdates(getLocationRequest(), mLocationCallback, Looper.getMainLooper())
                    .addOnFailureListener(myLocationListener::onLocationFailure);
        }
    
        private LocationRequest getLocationRequest() {
            LocationRequest locationRequest = new LocationRequest();
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            locationRequest.setInterval(INTERVAL_IN_MS);
            locationRequest.setFastestInterval(FASTEST_INTERVAL_IN_MS);
            locationRequest.setNumUpdates(NUMBER_OF_UPDATES);
            locationRequest.setMaxWaitTime(MAX_WAIT_TIME_IN_MS);
            return locationRequest;
        }
    
        public void resolveLocationSettings(FragmentActivity fragmentActivity, Exception exception) {
            ResolvableApiException resolvable = (ResolvableApiException) exception;
            try {
                resolvable.startResolutionForResult(fragmentActivity, MyLocationUtils.REQUEST_CODE_LOCATION_SETTINGS);
            } catch (IntentSender.SendIntentException e1) {
                e1.printStackTrace();
            }
        }
    
        public interface MyLocationListener {
    
            void onLocationSuccess(Location location);
    
            void onResolutionNeeded(Exception exception);
    
            void onLocationFailure(Exception exception);
        }
    }
    

    BaseLocationActivity.java:

    public abstract class LocationActivity extends AppCompatActivity {
    
        private MyLocationUtils myLocationUtils;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            myLocationUtils = new MyLocationUtils(this, new MyLocationUtils.MyLocationListener() {
                @Override
                public void onLocationSuccess(Location location) {
                    if (shouldBeAllowedToProceed())
                        LocationActivity.this.onLocationSuccess(location);
                }
    
                @Override
                public void onResolutionNeeded(Exception exception) {
                    exception.printStackTrace();
                    if (shouldBeAllowedToProceed())
                        LocationActivity.this.onResolutionNeeded(exception);
                }
    
                @Override
                public void onLocationFailure(Exception exception) {
                    exception.printStackTrace();
                    if (shouldBeAllowedToProceed())
                        LocationActivity.this.onLocationFailure(exception);
                }
            });
        }
    
        protected void getLocation() {
            myLocationUtils.getLocation();
        }
    
        protected void resolveLocationSettings(Exception exception) {
            myLocationUtils.resolveLocationSettings(this, exception);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == MyLocationUtils.REQUEST_CODE_LOCATION_SETTINGS) {
                final LocationSettingsStates locationSettingsStates = LocationSettingsStates.fromIntent(data);
                switch (resultCode) {
                    case Activity.RESULT_OK:
                        onResolveLocationSettingOk();
                        break;
                    case Activity.RESULT_CANCELED:
                        // The user was asked to change settings, but chose not to, 
                        // or on Android Oreo 8.1 Wifi Settings were not satisfied inspite of clicking OK, that results on Activity.RESULT_CANCELED
                        onResolveLocationSettingCancelled(locationSettingsStates);
                        break;
                    default:
                        break;
                }
            }
        }
    
        protected abstract void onResolveLocationSettingOk();
    
        protected void onResolveLocationSettingCancelled(LocationSettingsStates locationSettingsStates) {
            if (locationSettingsStates.isLocationPresent() && locationSettingsStates.isLocationUsable()) {
                onResolveLocationSettingOk();
            }
        }
    
        private boolean shouldBeAllowedToProceed() {
            return getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED);
        }
    
        public abstract void onLocationSuccess(Location location);
    
        public abstract void onResolutionNeeded(Exception exception);
    
        public abstract void onLocationFailure(Exception exception);
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            myLocationUtils.stopContinuousLocation();
        }
    }
    

    LocationFragment.java:

    public abstract class LocationFragment extends Fragment {
    
        private MyLocationUtils myLocationUtils;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            myLocationUtils = new MyLocationUtils(context, new MyLocationUtils.MyLocationListener() {
                @Override
                public void onLocationSuccess(Location location) {
                    if (shouldBeAllowedToProceed())
                        LocationFragment.this.onLocationSuccess(location);
                }
    
                @Override
                public void onResolutionNeeded(Exception exception) {
                    exception.printStackTrace();
                    if (shouldBeAllowedToProceed())
                        LocationFragment.this.onResolutionNeeded(exception);
                }
    
                @Override
                public void onLocationFailure(Exception exception) {
                    exception.printStackTrace();
                    if (shouldBeAllowedToProceed())
                        LocationFragment.this.onLocationFailure(exception);
                }
            });
        }
    
        protected void resolveLocationSettings(FragmentActivity appCompatActivity, Exception exception) {
            myLocationUtils.resolveLocationSettings(appCompatActivity, exception);
        }
    
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == MyLocationUtils.REQUEST_CODE_LOCATION_SETTINGS) {
                final LocationSettingsStates locationSettingsStates = LocationSettingsStates.fromIntent(data);
                switch (resultCode) {
                    case Activity.RESULT_OK:
                        onResolveLocationSettingOk();
                        break;
                    case Activity.RESULT_CANCELED:
                        // The user was asked to change settings, but chose not to
                        onResolveLocationSettingCancelled(locationSettingsStates);
                        break;
                    default:
                        break;
                }
            }
        }
    
        protected abstract void onResolveLocationSettingOk();
    
        protected void onResolveLocationSettingCancelled(LocationSettingsStates locationSettingsStates) {
            if (locationSettingsStates.isLocationPresent() && locationSettingsStates.isLocationUsable()) {
                onResolveLocationSettingOk();
            }
        }
    
        public void getLocation() {
            myLocationUtils.getLocation();
        }
    
        private boolean shouldBeAllowedToProceed() {
            return getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED);
        }
    
        public abstract void onLocationSuccess(Location location);
    
        public abstract void onResolutionNeeded(Exception exception);
    
        public abstract void onLocationFailure(Exception exception);
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            myLocationUtils.stopContinuousLocation();
        }
    }