Calling WifiManager.startLocalOnlyHotspot() throws SecurityException even after granting all required permissions on some devices
Asked Answered
H

1

2

I am working on a file sharing app. I need to turn on local only hotspot of a device programmatically by calling WifiManager.startLocalOnlyHotspot().

According to the android docs on this page - https://developer.android.com/reference/android/net/wifi/WifiManager#startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback,%2520android.os.Handler),

Applications need to have the following permissions to start LocalOnlyHotspot: Manifest.permission.CHANGE_WIFI_STATE and ACCESS_FINE_LOCATION. Callers without the permissions will trigger a SecurityException.

I have added both these permissions in my manifest and also granted ACCESS_FINE_LOCATION at runtime (coz it's a runtime permission (dangerous permission)).

But calling startLocalOnlyHotspot() still throws SecurityException in some devices.
Device in which SecurityException is thrown: Samsung Galaxy J7 Max (j7maxlte), Android 8.1 Device in which it works fine without throwing an exception: Redmi Note 7 Pro, Android 9 PKQ1.181203.001

What am I missing?

Honest answered 10/5, 2019 at 17:25 Comment(1)
Add ACCESS_WIFI_STATE permissionAedile
G
3

You need to enable location using GPS.

First of all, add the dependency for gms.

implementation 'com.google.android.gms:play-services-location:16.0.0'

After that, set up Location Services

  private void setupLocationServices() {
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(10);
    mLocationRequest.setSmallestDisplacement(10);
    mLocationRequest.setFastestInterval(10);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    LocationSettingsRequest.Builder builder = new
        LocationSettingsRequest.Builder();
    builder.addLocationRequest(mLocationRequest);

    task = LocationServices.getSettingsClient(this).checkLocationSettings(builder.build());

    locationSettingsResponseBuilder();
  }

LocationSettingsResponseBuilder:

  private void locationSettingsResponseBuilder() {
    task.addOnCompleteListener(task -> {
      try {
        LocationSettingsResponse response = task.getResult(ApiException.class);
        // All location settings are satisfied. The client can initialize location
        // requests here.

        //Everything is good. You can turn on hotspot here.

        //}
      } catch (ApiException exception) {
        switch (exception.getStatusCode()) {
          case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
            // Location settings are not satisfied. But could be fixed by showing the
            // user a dialog.
            try {
              // Cast to a resolvable exception.
              ResolvableApiException resolvable = (ResolvableApiException) exception;
              // Show the dialog by calling startResolutionForResult(),
              // and check the result in onActivityResult().
              resolvable.startResolutionForResult(
                  MainActivity.this,
                  101);
            } catch (IntentSender.SendIntentException e) {
              // Ignore the error.
            } catch (ClassCastException e) {
              // Ignore, should be an impossible 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;
        }
      }
    });
  }

Add this case to the onActivityResult method.

      case 101:
        final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
        switch (resultCode) {
          case Activity.RESULT_OK:
            // All required changes were successfully made
            Log.v("case 101", states.isLocationPresent() + "");

            //Everything is good. You can turn on hotspot here.

            break;
          case Activity.RESULT_CANCELED:
            // The user was asked to change settings, but chose not to
            Log.v("case 101", "Canceled");
            break;
          default:
            break;
        }
        break;

I recently created a demo app called Spotserve. That turns on wifi hotspot for all devices with API>=15 and hosts a demo server on that hotspot. You can check that for more details. Hope this helps!

Goldner answered 6/8, 2019 at 0:6 Comment(3)
Ok, this is good. But what if I just show a dialog to turn on GPS when Security Exception occurs. And then listen for changes in GPS state, and when user turns on GPS, try to start hotspot. Will that work the same? Or I need to request for location access in my code? Thanks for the answerHonest
First prompt the user to get 'Acces_fine_location' and then 'GPS'. You need to work with both. If both permissions are fulfilled, you can turn on the hotspot.Goldner
@mohit If you've any other questions feel free to ask.Goldner

© 2022 - 2024 — McMap. All rights reserved.