LocationSettingsRequest dialog to enable GPS - onActivityResult() skipped
Asked Answered
N

11

62

Part of my app requires location services, so if location is currently turned off, the app will prompt the user to enable it. Here is how I am doing it: (Also seen in this Stack Overflow answer)

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

PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());

result.setResultCallback(new ResultCallback<LocationSettingsResult>() 
{
     @Override
     public void onResult(LocationSettingsResult result) 
     {
         final Status status = result.getStatus();
         final LocationSettingsStates = result.getLocationSettingsStates();
         switch (status.getStatusCode()) 
         {
             case LocationSettingsStatusCodes.SUCCESS:
                 // All location settings are satisfied. The client can initialize location
                 // requests here.
                 ...
                 Log.d("onResult", "SUCCESS");
                 break;
             case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                 // Location settings are not satisfied. But could be fixed by showing the user
                 // a dialog.
                 Log.d("onResult", "RESOLUTION_REQUIRED");
                 try 
                 {
                     // Show the dialog by calling startResolutionForResult(),
                     // and check the result in onActivityResult().
                     status.startResolutionForResult(OuterClass.this, REQUEST_LOCATION);
                 } 
                 catch (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.
                 ...
                 Log.d("onResult", "UNAVAILABLE");
                 break;
         }
     }
 });

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    // This log is never called
    Log.d("onActivityResult()", Integer.toString(resultCode));

    final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
    switch (requestCode)
    {
        case REQUEST_LOCATION:
            switch (resultCode)
            {
                case Activity.RESULT_OK:
                {
                    // All required changes were successfully made
                    break;
                }
                case Activity.RESULT_CANCELED:
                {
                    // The user was asked to change settings, but chose not to
                    break;
                }
                default:
                {      
                    break;
                }
            }
            break;
    }
}

This code works well, however, onActivityResult() is always skipped. Whether or not the user presses Yes, No, or back from the Dialog, onActivityResult() doesn't run.

I need Android to call onActivityResult() so if the user chooses not to turn on location services, I can handle it appropriately.

Google's developer page (and the code above) explicitly says that onActivityResult() should be called. Anyone know why it's being skipped?

I also don't know what the purpose of this line is:

final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);

Thanks!

Edit: Basic information on the structure of my app:

  • This code is contained within the onResume() method of a Fragment which implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, and LocationListener to receive location updates. Example seen here.
  • In onLocationChanged() the Fragment will have a custom View call invalidate() and re-draw itself with updated information.
Nikethamide answered 5/7, 2015 at 22:22 Comment(0)
S
154

UPDATE

The original answer below is using Java and the now deprecated SettingsApi.

Here is a more modern approach using Kotlin and SettingsClient:

fun showEnableLocationSetting() {
    activity?.let {
        val locationRequest = LocationRequest.create()
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY

        val builder = LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest)

        val task = LocationServices.getSettingsClient(it)
                .checkLocationSettings(builder.build())

        task.addOnSuccessListener { response ->
            val states = response.locationSettingsStates
            if (states.isLocationPresent) {
                //Do something
            }
        }
        task.addOnFailureListener { e ->
            if (e is ResolvableApiException) {
                try {
                    // Handle result in onActivityResult()
                    e.startResolutionForResult(it,
                            MainActivity.LOCATION_SETTING_REQUEST)
                } catch (sendEx: IntentSender.SendIntentException) { }
            }
        }
    }
}

In MainActivity, define the constant:

companion object {
    const val LOCATION_SETTING_REQUEST = 999
}

ORIGINAL ANSWER:

It looks like the main issue is that you have all of the code in a Fragment, and since startResolutionForResult() needs an Activity passed into it, the Activity is what gets the onActivityResult() callback.

One way to get around that is to use the technique described here, manually call the Fragment's onActivityResult() method from the Activity when the result comes in.

I just got this simple example working.

First, the Activity, which adds the Fragment, and also has functionality to pass along the result of onActivityResult() to the Fragment:

public class MainActivity extends AppCompatActivity{

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

        lFrag = LocationFragment.newInstance();
        getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, lFrag).commit();

    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == LocationFragment.REQUEST_LOCATION){
            lFrag.onActivityResult(requestCode, resultCode, data);
        }
        else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
}

Here is the Fragment, which contains all of the functionality to show the dialog, and handle the result. In this simple example I just used Toast messages to verify that it is working as expected. Note that the main change that I've made here from the code in your question is the use of getActivity() to get the Activity reference needed for the call to startResolutionForResult().

public class LocationFragment extends Fragment
        implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {


    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    PendingResult<LocationSettingsResult> result;
    final static int REQUEST_LOCATION = 199;

    public static LocationFragment newInstance() {
        LocationFragment fragment = new LocationFragment();
        return fragment;
    }

    public LocationFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();
        mGoogleApiClient.connect();

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_location, container, false);
    }


    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onConnected(Bundle bundle) {

        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(30 * 1000);
        mLocationRequest.setFastestInterval(5 * 1000);

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

        result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, 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(
                                    getActivity(),
                                    REQUEST_LOCATION);
                        } 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;
                }
            }
        });

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        Log.d("onActivityResult()", Integer.toString(resultCode));

        //final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
        switch (requestCode)
        {
            case REQUEST_LOCATION:
                switch (resultCode)
                {
                    case Activity.RESULT_OK:
                    {
                        // All required changes were successfully made
                        Toast.makeText(getActivity(), "Location enabled by user!", Toast.LENGTH_LONG).show();
                        break;
                    }
                    case Activity.RESULT_CANCELED:
                    {
                        // The user was asked to change settings, but chose not to
                        Toast.makeText(getActivity(), "Location not enabled, user cancelled.", Toast.LENGTH_LONG).show();
                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                break;
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

}

Here are the results visually, first the dialog is shown if Location Mode is disabled:

enter image description here

Then, if the user clicks No, the result is passed from the Activity to the Fragment, which shows a Toast:

enter image description here

Same thing when the user clicks Yes, but with a success result, and Location Mode is enabled:

enter image description here

Note that it might be a better option to just keep all of this functionality in the Activity, and then call into a public method in the Fragment when the result comes in.

Here is fully working code for keeping the functionality in the Activity. Of course in this solution, you would need to add a call into the Fragment to update the state of Location Mode after onActivityResult() is called.

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


    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    PendingResult<LocationSettingsResult> result;
    final static int REQUEST_LOCATION = 199;

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

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

    }

    @Override
    public void onConnected(Bundle bundle) {

        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(30 * 1000);
        mLocationRequest.setFastestInterval(5 * 1000);

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

        result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, 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(
                                    MainActivity.this,
                                    REQUEST_LOCATION);
                        } catch (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;
                }
            }
        });

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        Log.d("onActivityResult()", Integer.toString(resultCode));

        //final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
        switch (requestCode)
        {
            case REQUEST_LOCATION:
                switch (resultCode)
                {
                    case Activity.RESULT_OK:
                    {
                        // All required changes were successfully made
                        Toast.makeText(MainActivity.this, "Location enabled by user!", Toast.LENGTH_LONG).show();
                        break;
                    }
                    case Activity.RESULT_CANCELED:
                    {
                        // The user was asked to change settings, but chose not to
                        Toast.makeText(MainActivity.this, "Location not enabled, user cancelled.", Toast.LENGTH_LONG).show();
                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                break;
        }
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }
}
Shellans answered 4/8, 2015 at 18:31 Comment(13)
How to refresh the location on ActivityResultShovelnose
You will need to request location updates once the user has enabled location services. See here: #34582870Shellans
Hi @DanielNugent thanks for the post. I have a situation where I am checking if the user's settings are as expected every time i click on a button. Which simply means, I am calling result.setResultCallback every time to check if the user has changed the setting. Strangely, this works only first time. onResult will never get called . i have a SO question on the same #38152150. can you please helpDearth
One of the fine answers for 6.0 devices. However, I am calling LocationFragment inside another fragment & not getting Toast at all. Will you please tell me the problem?Optician
Also, if I try the same code with Activity/Fragment then it works fine but fragment to fragment it doesn't ToastOptician
@vvb The result must be handled in the ActivityShellans
I've wrapped the solution in a library. More info about that in my answer here: https://mcmap.net/q/169186/-turn-gps-on-programmatically-like-ola-cabs-android-appExcrete
I've called a helper method, which has onActivityResult but the helper class method is skipped and activity's onActivityResult is calledAttainment
it is returning 0 every timeTeacher
If the user turned on location from this dialog and then turned Off from the top menu then again try to turn on location from app this dialog is didn't shown next time.Duky
@Daniel Nugent, According to what i understood, LocationSettingRequest check is done only once before requesting for location updates right ?? After starting request for location updates, after some time if the user disable the gps, will the LocationSettinsRequest onFailureCallback() gets called again ?? I think this is one time call back to check if gps is ON before requesting for location updates. What we can do if user turns OFF gps after some time ?? may be we should periodically check if gps is turned ON.Copepod
@Daniel Nugent, Can we call LocationSettingRequest from a foreground service ?? Because i'm requesting for location updates from a foreground serrvice.Copepod
@PradeepkumarReddy It sounds like the best solution for you would be to incorporate a listener on the Location settings, see here: #36325588Shellans
D
42

You need to add this to your result callback:

case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
    try {
        fragment.startIntentSenderForResult(status.getResolution().getIntentSender(), REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null);
    } catch (IntentSender.SendIntentException e) {
        // Ignore the error.
    }
    break;

onActivityResult will be called on your fragment, you don't need to call it manually in your activity. This is essentially how startResolutionForResult works.

Doriandoric answered 19/9, 2016 at 17:44 Comment(6)
please add backticks wrappers around your inline code bitMehalek
I had commented this line : status.startResolutionForResult(hostActivity, REQUEST_CHECK_SETTINGS); and used your code and its working without having to override onActiivtyResult in main activity.Tuberculosis
This should be the accepted answer. working perfectly.Behlau
You can jump into the source for Status.startResolutionForResult also and verify that this is exactly what it's doing. Probably a good idea to also make the same check for Status.hasResolution also though.Slattern
Can we call LocationSettingRequest from a foreground service ?? Because i'm requesting for location updates from a foreground serrvice.Copepod
startIntentSenderForResult is now deprecated. Use registerForActivityResult.Miff
S
16

When you need to resolve the Status or the ResolvableApiException, I suggest you to leverage the activity.registerForActivityResult API in place of startResolutionForResult:

ActivityResultLauncher<IntentSenderRequest> launcher = activity.registerForActivityResult(
        new ActivityResultContracts.StartIntentSenderForResult(),
        new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    // All required changes were successfully made
                } else {
                    // The user was asked to change settings, but chose not to
                }
            }
        });

IntentSenderRequest intentSenderRequest = new IntentSenderRequest.Builder(exception.getResolution()).build();
launcher.launch(intentSenderRequest);

You are using Java, but in case Kotlin is needed:

val launcher = activity.registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            // User accepted
        } else {
            // User didn't accepted
        }
    }

val intentSenderRequest = IntentSenderRequest.Builder(exception.resolution).build()
launcher.launch(intentSenderRequest)
Story answered 22/1, 2021 at 10:49 Comment(2)
exactly what I was searching, how to leverage the activity result API for this, so this whole location fetch, permission check, settings can fit in one extension function and I simply call it from wherever I need..no fusApatetic
This should be mark now as an answer, the old marked answer was too outdated. This is the latest approach as of this moment.Ride
M
5

If you want results back to your fragment than use

startIntentSenderForResult(status.getResolution().getIntentSender(), REQUEST_CODE_LOCATION_SETTING, null, 0, 0, 0, null);

instead of status.startResolutionForResult(YourActivity, LOCATION_REQUEST);

USING above method will deliver result back to your fragment only.

Meitner answered 4/9, 2018 at 6:3 Comment(5)
Thanks, but this is a copy of Saša Tarbuk answer (https://mcmap.net/q/168022/-locationsettingsrequest-dialog-to-enable-gps-onactivityresult-skipped).Miff
Can we call LocationSettingRequest from a foreground service ?? Because i'm requesting for location updates from a foreground serrvice.Copepod
@user3410835 No you can't.Meitner
@Ghodasara Bhaumik. Thanks. reason ??Copepod
@user3410835 because to enable location android has to show dialog and to show dialog it needs context of your app. If app has fore ground service running means app is not up and android can't find context of your app to show Location Enable Dialog.Meitner
N
4

For Kotlin Users

This solution is applicable for both Activity and Fragment by doing one following change in checkLocationSetting():

For Activity resolvableApiException.startResolutionForResult(this@MainActivity, REQUEST_CHECK_SETTING)

For Fragment startIntentSenderForResult(resolvableApiException.resolution.intentSender, REQUEST_CHECK_SETTING, null, 0, 0,0,null)

By using LocationSettingsResponse this task can be achieved.

inside MainActivity.kt


    private fun checkLocationSetting()
        {
            locationRequest = LocationRequest.create()
            locationRequest.apply {
                priority=LocationRequest.PRIORITY_HIGH_ACCURACY
                interval = 5000
                fastestInterval = 2000
            }
    
            val builder = LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest)
            builder.setAlwaysShow(true)
    
            val result: Task<LocationSettingsResponse> = LocationServices.getSettingsClient(applicationContext)
                .checkLocationSettings(builder.build())
    
            result.addOnCompleteListener {
                try{
                    val response: LocationSettingsResponse = it.getResult(ApiException::class.java)
                    Toast.makeText(this@MainActivity, "GPS is On", Toast.LENGTH_SHORT).show()
                    Log.d(TAG, "checkSetting: GPS On")
                }catch(e:ApiException){
    
                    when(e.statusCode){
                        LocationSettingsStatusCodes.RESOLUTION_REQUIRED ->{
                            val resolvableApiException = e as ResolvableApiException
                            resolvableApiException.startResolutionForResult(this@MainActivity, REQUEST_CHECK_SETTING)
                            Log.d(TAG, "checkSetting: RESOLUTION_REQUIRED")
                        }
    
                        LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
                            // USER DEVICE DOES NOT HAVE LOCATION OPTION
                        }
                    }
                }
            }
        }

onActivityResult

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when(requestCode)
        {
            REQUEST_CHECK_SETTING ->{
                when(resultCode){
                    Activity.RESULT_OK->{
                        Toast.makeText(this@MainActivity, "GPS is Turned on", Toast.LENGTH_SHORT).show()
                    }
                    Activity.RESULT_CANCELED ->{
                        Toast.makeText(this@MainActivity, "GPS is Required to use this app", Toast.LENGTH_SHORT).show()
                    }
                }
            }
        }
    }

Link to complete code MainActivity.kt

Output:

Link to complete code MainActivity.kt

Nowt answered 13/7, 2021 at 9:23 Comment(3)
REQUEST_CHECK_SETTING is not getting imported for me...Whaleboat
it's a constant. you can declare it yourself.Nowt
here is the link to mainActivity.java: gist.github.com/ShoaibKakal/4d07b4001e34cb770d3ee7cae294f7b0Nowt
M
1

For handling enable location from fragment below is the latest code that can be used. Settings API is now deprecated. Below is the method to use SettingsClient API.

Also I noticed that, in Android 10 devices even when user enable the location; status result in onActivityResult is coming as RESULT_CANCELED, I couldn't find a way to get rid of that issue in Android 10 device where as in Android PIE the result code is RESULT_OK. So only way to detect whether user enabled it or not is by explicitly checking whether location is enabled using LocationManagerCompat API for Android 10 devices

private fun enableLocationIfRequired() {
    val builder = LocationSettingsRequest.Builder()
        .addLocationRequest(LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY))
        .setAlwaysShow(true)

    val settingsClient = LocationServices.getSettingsClient(context!!)

    val task = settingsClient!!.checkLocationSettings(builder.build())
    task.addOnCompleteListener {
        try {
            val response = it.getResult(ApiException::class.java)

            //Success
            Log.d(javaClass.simpleName, "Location is enabled")

        } catch (exception: ApiException) {
            Log.d(javaClass.simpleName, "exception thrown: ${exception.statusCode}")
            when (exception.statusCode) {
                LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
                    // Location settings are not satisfied. But could be fixed by showing the
                    // user a dialog.
                    try {
                        // Cast to a resolvable exception.
                        val resolvable = exception as ResolvableApiException
                        // Show the dialog by calling startResolutionForResult(),
                        // and check the result in onActivityResult().
                        Log.d(javaClass.simpleName, "startResolutionForResult called")

                        this.startIntentSenderForResult(
                            resolvable.resolution.intentSender,
                            RC_LOCATION_ENABLE,
                            null, 0, 0, 0, null
                        )

                    } catch (e: IntentSender.SendIntentException) {
                        // Ignore the error.
                        Log.d(javaClass.simpleName, "IntentSender.SendIntentException")
                    } catch (e: ClassCastException) {
                        // Ignore, should be an impossible error.
                        Log.d(javaClass.simpleName, "ClassCastException")
                    }
                }
                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.
                }
            }
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        RC_LOCATION_ENABLE -> {
            if (resultCode == Activity.RESULT_OK) {
                Log.d(javaClass.simpleName, "Location is enabled by user")
            } else {
                Log.d(javaClass.simpleName, "Location enable request is cancelled by user")
            }
            val lm = context!!.getSystemService(LOCATION_SERVICE) as LocationManager
            if (LocationManagerCompat.isLocationEnabled(lm)) {
                Log.d(javaClass.simpleName, "Location is enabled by user")
            } else {
                Log.d(javaClass.simpleName, "Location enable request is cancelled by user")
            }
        }
    }

}
Misinterpret answered 24/10, 2019 at 10:46 Comment(0)
M
1

Thanks to @gianlucaparadise solution you should write for new API:

Fragment (or maybe Activity):

private lateinit var checkLocationSettings: ActivityResultLauncher<IntentSenderRequest>

override fun onCreate(savedInstanceState: Bundle?) {
    checkLocationSettings = 
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                // GPS is turned on in system settings.
            }
    }
}

Fragment or utility class where you want to enable GPS (see 1 or 2):

.addOnFailureListener(context) { e ->
    when ((e as? ApiException)?.statusCode) {
        LocationSettingsStatusCodes.RESOLUTION_REQUIRED ->
            try {
                // Cast to a resolvable exception.
                val resolvable = e as ResolvableApiException
                // Old API: show the dialog by calling startResolutionForResult(),
                // and check the result in onActivityResult().
                // New API: call registerForActivityResult::launch
                // and check the result in callback.
                val intentSenderRequest =
                    IntentSenderRequest.Builder(resolvable.resolution).build()
                checkLocationSettings.launch(intentSenderRequest)
            } catch (sie: IntentSender.SendIntentException) {
                Timber.e("GPS: Unable to execute request.")
            } catch (cce: java.lang.ClassCastException) {
                // Ignore, should be an impossible error.
                Timber.e("GPS: Unable to execute request, ClassCastException.")
            }

Deprecated API variant for Fragment and onActivityResult: LocationSettingsRequest dialog to enable GPS - onActivityResult() skipped.

Miff answered 20/1, 2021 at 19:52 Comment(3)
Any source that says startResolutionForResult is the old and registerForActivityResult is newer?Illampu
@Dr.jacky, sorry, I don't have this project now. I used startResolutionForResult and registerForActivityResult, the first one didn't lead to a result in a fragment or was deprecated (I don't remember).Miff
@Dr.jacky, please, see #67983663, developer.android.com/jetpack/androidx/releases/…. I meant fragments, in activities startResolutionForResult is still used (developer.android.com/reference/android/app/…. Also onActivityResult is deprecated.Miff
T
0

I see that you use different constants REQUEST_CHECK_SETTINGS and REQUEST_LOCATION for request code. Do they have same value?

For the code:final LocationSettingsStates states = LocationSettingsStates.fromIntent(intent);.
The purpose of above code is to get the current status of Location setting(like use Network, GPS, ...) after changed the setting.
Also, in your code, I think it's should be LocationSettingsStates.fromIntent(data); because the intent doesn't exixst here, maybe it's just a typo.

Thymus answered 4/8, 2015 at 4:17 Comment(1)
Thanks. For this question, I copied the code directly from Google's developer pages. Those errors were not present in my app, but they weren't the problem anyway. If you look at onActivityResult() now, you'll see a Log function that is never even called.Nikethamide
R
0

Its because of all google api codes present in the Fragments.. Try the following it will help to overcome...

1.Create a empty constructor for your fragments.

2.need oncreate() method before the onCreateView()...

3.paste the Google api code inside the oncreate()....

    public mainFragment(){

}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        buildGoogleApiClient();
        buildLocationSettingsRequest();

        checkLocationSettings();
        mGoogleApiClient.connect();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

For your Reference...

Click here...

Rottweiler answered 8/6, 2016 at 10:36 Comment(0)
S
0

Saving fragment field in activity (as Daniel suggested) is not often a good decision, cause imagine you have multiple fragments and each contains location code. I did it in a different manner:

public class MainActivity extends Activity implements PlaceFragment.SettingsModifyHandler {

    private static final int LOCATION_SETTINGS_RESULT = 1;
    private OnResultCallback placeCallback;

    ...

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == LOCATION_SETTINGS_RESULT) {
            if (resultCode == Activity.RESULT_OK) {
                placeCallback.resultOk();
            } else {
                placeCallback.resultFail();
            }
        placeCallback = null;
        }
    }

    @Override
    public void handle(IntentSender intentSender, OnResultCallback callback) {
        placeCallback = callback;
        try {
            startIntentSenderForResult(intentSender, LOCATION_SETTINGS_RESULT, null, 0, 0, 0);
        } catch (IntentSender.SendIntentException e) {
            callback.resultFail();
        }
    }
}

public class PlaceFragment extends Fragment {

    private SettingsModifyHandler settingsModifyHandler;

    ...

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (context instanceof SettingsModifyHandler) {
            settingsModifyHandler = (SettingsModifyHandler) context;
        } else {
            throw new RuntimeException("Parent activity must implement PlaceFragment.SettingsModifyHandler interface");
        }
    }

    /* Callback from module, where you implemented status.getStatusCode().LocationSettingsStatusCodes.RESOLUTION_REQUIRED case
    (status is instance of com.google.android.gms.common.api.Status)
    You provide intentSender here through status.getResolution().getIntentSender() */
    @Override
    public void placeLoadError(IntentSender sender) {
        TextView view_text = (TextView) root.findViewById(R.id.text_error);
        TextView view_btn = (TextView) root.findViewById(R.id.btn_reply);

        view_text.setText("Need to change location settings");
        view_btn.setText("Change");
        view_btn.setOnClickListener(v -> {
            settingsModifyHandler.handle(sender, new SettingsModifyHandler.OnResultCallback() {
                @Override
                public void resultOk() {
                    presenter.loadPlace(placeId);
                }

                @Override
                public void resultFail() {
                    ToastUtils.show("You should change location settings!");
                }
            });
        });
    }

    public interface SettingsModifyHandler {
        void handle(IntentSender intentSender, OnResultCallback callback);

        interface OnResultCallback {
            void resultOk();
            void resultFail();
        }
    }
}
Sundial answered 13/6, 2017 at 7:59 Comment(0)
E
0
    super.onActivityResult(requestCode, resultCode, data)

Needs to be called as first thing in onActivityResult...

Eldenelder answered 29/2 at 10:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.