I am developing an android app which needs to activate the GPS.
I read a lot of topics in a lot of forums and the answer I've found is:
it's not possible
But... the "Cerberus" APP turns my GPS on... so... it's possible!
Can anyone help me with this?
No, it's impossible, and inappropriate. You can't just manage the user's phone without their authority. The user must interact to enable GPS.
From Play Store:
"Cerberus automatically enables GPS if it is off when you try to localize your device (only on Android < 2.3.3) and you can protect it from unauthorized uninstalling - more info in the app configuration."
You can do something like this:
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
I think we have more better version to enable the location without opening the settings just like google map works.
It will looks like this -
Add Dependency in gradle -
compile 'com.google.android.gms:play-services-location:10.0.1'
public class MapActivity extends AppCompatActivity {
protected static final String TAG = "LocationOnOff";
private GoogleApiClient googleApiClient;
final static int REQUEST_LOCATION = 199;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setFinishOnTouchOutside(true);
// Todo Location Already on ... start
final LocationManager manager = (LocationManager) MapActivity.this.getSystemService(Context.LOCATION_SERVICE);
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(MapActivity.this)) {
Toast.makeText(MapActivity.this,"Gps already enabled",Toast.LENGTH_SHORT).show();
}
// Todo Location Already on ... end
if(!hasGPSDevice(MapActivity.this)){
Toast.makeText(MapActivity.this,"Gps not Supported",Toast.LENGTH_SHORT).show();
}
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(MapActivity.this)) {
Log.e("TAG","Gps already enabled");
Toast.makeText(MapActivity.this,"Gps not enabled",Toast.LENGTH_SHORT).show();
enableLoc();
}else{
Log.e("TAG","Gps already enabled");
Toast.makeText(MapActivity.this,"Gps already enabled",Toast.LENGTH_SHORT).show();
}
}
private boolean hasGPSDevice(Context context) {
final LocationManager mgr = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
if (mgr == null)
return false;
final List<String> providers = mgr.getAllProviders();
if (providers == null)
return false;
return providers.contains(LocationManager.GPS_PROVIDER);
}
private void enableLoc() {
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(MapActivity.this)
.addApi(LocationServices.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
googleApiClient.connect();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d("Location error","Location error " + connectionResult.getErrorCode());
}
}).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);
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();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(MapActivity.this, REQUEST_LOCATION);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
}
}
});
}
}
There used to be an exploit that allowed the GPS to be turned on by an app with no special permissions. That exploit no longer exists as of 2.3 (in most ROMs). Here's another post that talks about it,
How can I enable or disable the GPS programmatically on Android?
"GPS enabled" is a secure setting, so you must have WRITE_SECURE_SETTINGS permission. This is a signature protected permission however, so you app will not be granted this unless it is signed with the manufacturer's platform certificate.
The correct thing is to send the user to the location settings page, and let them enable GPS if they wish. e.g.,
Intent i = new
Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(i);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.gps_disabled_message)
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
This creates an alert and allows the user to go to the settings screen and hit the back button to come right back to your app. The power widget exploit doesn't work beyond 2.3 to my knowledge.
Use this code
//turnGPSON called After setcontentView(xml)
private void turnGPSOn() {
String provider = android.provider.Settings.Secure.getString(
getContentResolver(),
android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (!provider.contains("gps")) { // if gps is disabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings",
"com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}**
The GoogleApiClient has been deprecated, we need to use SettingsClient and GoogleApi to enable GPS without going to the Location Settings just like Google Maps, OLA, Zomato etc. Below code supports any of the Android Version starting from 4.4 or lower to 11+
dependency required in gradle file:
implementation 'com.google.android.gms:play-services-location:17.1.0'
To check GPS state ON or OFF:
private static LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
public static boolean isGpsEnabled(){
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
If GPS is already enabled then we will display toast notification otherwise will ask to turn the GPS on.
//Defining constant request code, add in your activity class
private static final int REQUEST_CHECK_SETTINGS = 111;
if(!isGpsEnabled()){
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true); //this displays dialog box like Google Maps with two buttons - OK and NO,THANKS
Task<LocationSettingsResponse> task =
LocationServices.getSettingsClient(this).checkLocationSettings(builder.build());
task.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
#Override
public void onComplete(Task<LocationSettingsResponse> task) {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
// All location settings are satisfied. The client can initialize location
// requests 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(
YOUR_ACTIVITY.this,
REQUEST_CHECK_SETTINGS);
} 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;
}
}
}
});
} else {
Toast.makeText(getApplicationContext(), "GPS is already Enabled!", Toast.LENGTH_SHORT).show();
}
}
If GPS is not ON, then flow will come to RESOLUTION_REQUIRED and that will call startResolutionForResult which will be handled by onActivityResult
Now, add onActivityResult method -
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode) {
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
// All required changes were successfully made
Toast.makeText(getApplicationContext(),"User has clicked on OK - So GPS is on", Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
// The user was asked to change settings, but chose not to
Toast.makeText(getApplicationContext(),"User has clicked on NO, THANKS - So GPS is still off.", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
break;
}
}
If resultCode is RESULT_OK that means user allowed to turn GPS on else for RESULT_CANCELED, you can again ask or show the rationale dialog.
You can wrap above code in method and call wherever you require
While building LocationRequest you can set Interval, Priority, SmallestDisplacement, FastestInterval, etc as per you required by your app.
We have used Task api instead of PendingResult
For Official Document, refer - https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
you might want to check out this thread
How can I enable or disable the GPS programmatically on Android?
here are the codes copied from that thread
private void turnGPSOn(){
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(!provider.contains("gps")){ //if gps is disabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
private void turnGPSOff(){
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(provider.contains("gps")){ //if gps is enabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
but the solution is not recommended as it will not be available to android version > 2.3 supposingly.. do check the comments
Related
My app works fine in turning location on and setPriority to HIGH when the Location setting is off, but it crashes when the location is set as GPS LocationRequest.PRIORITY_LOW_POWER instead of displaying the dialog to change to LocationRequest.PRIORITY_HIGH_ACCURACY
Here is the method that access the SettingClient
public void locationSettingRequest() {
LocationRequest mLocationRequestHighAccuracy = new LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationRequest mLocationRequestBalancedPowerAccuracy = new LocationRequest().setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequestHighAccuracy)
.addLocationRequest(mLocationRequestBalancedPowerAccuracy);
Task<LocationSettingsResponse> result =
LocationServices.getSettingsClient(this).checkLocationSettings(builder.build());
result.addOnCompleteListener(task -> {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
// All location settings are satisfied. The client can initialize location
// requests here.
getLoc();
} 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(
SignUpActivity.this,
REQUEST_CHECK_SETTINGS);
} 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;
}
}
});
}
and I received the response in the OnActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
if (requestCode == REQUEST_CHECK_SETTINGS) {
switch (resultCode) {
case Activity.RESULT_OK:
// All required changes were successfully made
getLoc();
break;
case Activity.RESULT_CANCELED:
finish();
break;
default:
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
How do I get the location to change from LocationRequest.PRIORITY_LOW_POWER to HIGH_ACCURACY?
This is how I solved it, I checked if the LocationManager.NETWORK_PROVIDER is enable. If it not, I display a message to prompt user to change location mode to HIGH_ACCURACY. I then call settingRequest if NETWORK_PROVIDER is enable.
Not sure if it's the right way, but it worked.
public void checkLocationMode() {
LocationManager loc = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (!loc.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Toast.makeText(this, "Turn location mode to High Accuracy.", Toast.LENGTH_LONG).show();
Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(myIntent);
} else {
settingRequest();
}
}
in my app I have the option for the user to open the settings and allow location. How can I know that the user turned on the location after I navigated into the settings screen? This is how start the settings activity.
if(!gps_enabled && !network_enabled) {
// notify user
new AlertDialog.Builder(this)
.setMessage(R.string.gps_network_not_enabled)
.setPositiveButton(R.string.open_location_settings, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), isGpsTurnedOnResult );
}
}).setNegativeButton(R.string.Cancel,null)
.show();
}
This is how I try to get the result:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
When I check data I see that it's null, is there a way I can know that the user turned the location on? Of course I can check it using LocationManager, but this is not the solution I want unless it's the only thing that possible.
Build location setting
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
// ...
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
Prompt the user to change location settings
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
});
task.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(MainActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
}
});
Before I explain my scenario here is my code.
public class Permission extends AppCompatActivity implements ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<LocationSettingsResult> {
public static final int MULTIPLE_PERMISSIONS = 10;
Timer myTimer;
TimerTask doThis;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest locationRequest;
int REQUEST_CHECK_SETTINGS = 100;
String[] permissions = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
/* TODO : Grant the following permissions
* 1. Request Read External Storage OK
* 2. Request Write External Storage OK
* 3. Request Read Intenal Storage OK
* 4. Request Write External Storage OK
* 5. Request GPS (2) OK
* 6. Request Camera OK
* */
if (checkPermissions()) {
Intent standby = new Intent(Permission.this, standby.class);
startActivity(standby);
}
Button btn_enable = findViewById(R.id.enable);
btn_enable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
EnablePermissions();
}
});
/* Check if permission is done */
myTimer = new Timer();
int delay = 0;
int period = 1000;
doThis = new TimerTask() {
public void run() {
if (checkPermissions()) {
myTimer.cancel();
Intent standby = new Intent(Permission.this, standby.class);
startActivity(standby);
}
}
};
myTimer.scheduleAtFixedRate(doThis, delay, period);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Toast.makeText(this, ""+requestCode, Toast.LENGTH_SHORT).show();
if (requestCode == REQUEST_CHECK_SETTINGS) {
if (resultCode == RESULT_OK) {
//Toast.makeText(getApplicationContext(), "GPS enabled", Toast.LENGTH_LONG).show();
} else {
//Toast.makeText(getApplicationContext(), "GPS is not enabled", Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(this, p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
return false;
}
return true;
}
private boolean EnablePermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(this, p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(
mGoogleApiClient,
builder.build()
);
result.setResultCallback(this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onResult(#NonNull LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// NO need to show the dialog;
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// GPS turned off, Show the user a dialog
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(Permission.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
//failed to show dialog
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are unavailable so not possible to show any dialog now
break;
}
}
}
and the output of that is this.
and
my question is how can i make it as one? I mean a group permission that will allow each one of it.
I dont know what to do. what Im pointing is to merge all permissions as one then if the users did not select the last one still it is ok.
sorry for the confusion. as based on my code the 1st permission enables 3 settings and the second one enables the location service. Basically both of them lies on the different dialog which makes it 2 appear two times. I want is to merge them as one group permission (based on 1st image) so it will use the one dialog a dialog that will let the user to enable the following (Storage,Camera,Location and Location Services)
Firstly, your code seems to be missing the onRequestPermissionsResult method that would handle what happens after the user accepts / rejects the individual permissions. As seen in the link, you can use a switch statement and have logic for each permission, so you can decide which is optional and which is mandatory, and change the UI and application behavior accordingly.
Secondly, if what you are asking is whether all permissions (from multiple groups) can be granted in a single dialog box (as opposed to one for each group), then it is not possible.
According to the official docs :
Note: When your app calls requestPermissions(), the system shows a standard dialog box to the user. Your app cannot configure or alter that dialog box. If you need to provide any information or explanation to the user, you should do that before you call requestPermissions(), as described in Explain why the app needs permissions.
Thus, in your case, the user would get 3 permission dialogs - one each for Storage, Contacts and Location permission groups.
The last dialog that prompts the user to enable location isn't related to permissions, it just toggles the setting for GPS.
How can I prompt the user to turn on Location?
The app is supposed to filter a list of locations with the current location of the user. If the user has the Location service turned off, the app should prompt the user asking for the Location to be turned on.
For instance Trip Advisor app does this:
( Not sure if I can post other apps screenshots here, but if I shouldn't be doing it, please say so. And apologize for the full sized images, tried to make them smaller, but SO didn't liked it... )
In the first image, you can see I have the Location service turned off. The, after opening the Trip Advisor app, and tapping the Near me now option, I'm prompted with the second image, where I'm asked to Turn on Location services. After I tap the button, a dialog shows up so I can allow, or disallow, the Location service to be turned on. If I tap OK, the Location service is turned on on the device, and the app consumes it.
How can I achieve this?
Found the solution I was asking for.
Requirements
Nuget Xamarin.GooglePlayServices.Location
Code
Int64
interval = 1000 * 60 * 1,
fastestInterval = 1000 * 50;
try {
GoogleApiClient
googleApiClient = new GoogleApiClient.Builder( this )
.AddApi( LocationServices.API )
.Build();
googleApiClient.Connect();
LocationRequest
locationRequest = LocationRequest.Create()
.SetPriority( LocationRequest.PriorityBalancedPowerAccuracy )
.SetInterval( interval )
.SetFastestInterval( fastestInterval );
LocationSettingsRequest.Builder
locationSettingsRequestBuilder = new LocationSettingsRequest.Builder()
.AddLocationRequest( locationRequest );
locationSettingsRequestBuilder.SetAlwaysShow( false );
LocationSettingsResult
locationSettingsResult = await LocationServices.SettingsApi.CheckLocationSettingsAsync(
googleApiClient, locationSettingsRequestBuilder.Build() );
if( locationSettingsResult.Status.StatusCode == LocationSettingsStatusCodes.ResolutionRequired ) {
locationSettingsResult.Status.StartResolutionForResult( this, 0 );
}
} catch( Exception exception ) {
// Log exception
}
With this code, if the locationSettingsResult.Status.StatusCode is LocationSettingsStatusCodes.ResolutionRequired ( 6 ) it means -- probably -- that the Location is turned off, although I've found one situation that it didn't return the value when the device had the option turned off. After turning on and off, it worked, might be a bug on the device, or not.
Suppose your are doing all this stuff in an Activity name LocationActivity. You need to implement some callbacks for this purpose. Below is the code with comments so you can easily understand which method do what and when is called.
Keep in mind to add permissions in app manifest file:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Code for Ativity:
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v13.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
public class LocationActivity extends FragmentActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
// Unique tag for the error dialog fragment
private static final String DIALOG_ERROR = "dialog_error";
// Bool to track whether the app is already resolving an error
private boolean mResolvingError = false;
// Request code to use when launching the resolution activity
private static final int REQUEST_RESOLVE_ERROR = 555;
int ACCESS_FINE_LOCATION_CODE = 3310;
int ACCESS_COARSE_LOCATION_CODE = 3410;
private GoogleApiClient mGoogleApiClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Build Google API Client for Location related work
buildGoogleApiClient();
}
// When user first come to this activity we try to connect Google services for location and map related work
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
// Google Api Client is connected
#Override
public void onConnected(Bundle bundle) {
if (mGoogleApiClient.isConnected()) {
//if connected successfully show user the settings dialog to enable location from settings services
// If location services are enabled then get Location directly
// Else show options for enable or disable location services
settingsrequest();
}
}
// This is the method that will be called if user has disabled the location services in the device settings
// This will show a dialog asking user to enable location services or not
// If user tap on "Yes" it will directly enable the services without taking user to the device settings
// If user tap "No" it will just Finish the current Activity
public void settingsrequest() {
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(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
if (mGoogleApiClient.isConnected()) {
// check if the device has OS Marshmellow or greater than
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (ActivityCompat.checkSelfPermission(LocationActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(LocationActivity.this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(LocationActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, ACCESS_FINE_LOCATION_CODE);
} else {
// get Location
}
} else {
// get Location
}
}
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(LocationActivity.this, REQUEST_RESOLVE_ERROR);
} 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;
}
}
});
}
// This method is called only on devices having installed Android version >= M (Marshmellow)
// This method is just to show the user options for allow or deny location services at runtime
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 3310: {
if (grantResults.length > 0) {
for (int i = 0, len = permissions.length; i < len; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
// Show the user a dialog why you need location
} else if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
// get Location
} else {
this.finish();
}
}
}
return;
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_RESOLVE_ERROR) {
mResolvingError = false;
switch (resultCode) {
case Activity.RESULT_OK:
// get location method
break;
case Activity.RESULT_CANCELED:
this.finish();
break;
}
}
}
#Override
public void onConnectionSuspended(int i) {
}
// When there is an error connecting Google Services
#Override
public void onConnectionFailed(ConnectionResult result) {
if (mResolvingError) {
// Already attempting to resolve an error.
return;
} else if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
// Show dialog using GoogleApiAvailability.getErrorDialog()
showErrorDialog(result.getErrorCode());
mResolvingError = true;
}
}
/* Creates a dialog for an error message */
private void showErrorDialog(int errorCode) {
// Create a fragment for the error dialog
ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
// Pass the error that should be displayed
Bundle args = new Bundle();
args.putInt(DIALOG_ERROR, errorCode);
dialogFragment.setArguments(args);
dialogFragment.show(getSupportFragmentManager(), "errordialog");
}
/* Called from ErrorDialogFragment when the dialog is dismissed. */
public void onDialogDismissed() {
mResolvingError = false;
}
/* A fragment to display an error dialog */
public static class ErrorDialogFragment extends DialogFragment {
public ErrorDialogFragment() {
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the error code and retrieve the appropriate dialog
int errorCode = this.getArguments().getInt(DIALOG_ERROR);
return GoogleApiAvailability.getInstance().getErrorDialog(
this.getActivity(), errorCode, REQUEST_RESOLVE_ERROR);
}
#Override
public void onDismiss(DialogInterface dialog) {
((LocationActivity) getActivity()).onDialogDismissed();
}
}
// Connect Google Api Client if it is not connected already
#Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
// Stop the service when we are leaving this activity
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
}
}
You can read the official docs here
You can use the following class for moving user to settings. First check for the location if it is not available call showSettingAlert
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS is settings");
// Setting Dialog Message
alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// on pressing cancel button
alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
Use the below code snippet to open Device settings screen.
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
else use settings API for permission dialog
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(mContext).addApi(LocationServices.API).build();
googleApiClient.connect();
LocationRequest lReq = LocationRequest.create();
lReq.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
lReq.setInterval(10000);
lReq.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder lBuilder = new LocationSettingsRequest.Builder().addLocationRequest(lReq);
lBuilder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, lBuilder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
break;
}
}
});
Try
private void turnGPSOn(){
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(!provider.contains("gps")){ //if gps is disabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
private void turnGPSOff(){
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(provider.contains("gps")){ //if gps is enabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
private boolean canToggleGPS() {
PackageManager pacman = getPackageManager();
PackageInfo pacInfo = null;
try {
pacInfo = pacman.getPackageInfo("com.android.settings", PackageManager.GET_RECEIVERS);
} catch (NameNotFoundException e) {
return false; //package not found
}
if(pacInfo != null){
for(ActivityInfo actInfo : pacInfo.receivers){
//test if recevier is exported. if so, we can toggle GPS.
if(actInfo.name.equals("com.android.settings.widget.SettingsAppWidgetProvider") && actInfo.exported){
return true;
}
}
}
return false; //default
}
How to turn on location programmatically in android by showing a location dialog in your app to the user.
This is simple code :
First, add dependencies of google service location
dependencies {
implementation 'com.google.android.gms:play-services-location:17.0.0'
}
in MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button TurnGPSOn;
private LocationRequest locationRequest;
private static final int REQUEST_CHECK_SETTINGS = 10001;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TurnGPSOn = findViewById(R.id.location_btn);
TurnGPSOn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(2000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
Task<LocationSettingsResponse> result = LocationServices.getSettingsClient(getApplicationContext())
.checkLocationSettings(builder.build());
result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
#Override
public void onComplete(#NonNull Task<LocationSettingsResponse> task) {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
Toast.makeText(MainActivity.this, "GPS is already tured on", Toast.LENGTH_SHORT).show();
} catch (ApiException e) {
switch (e.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException resolvableApiException = (ResolvableApiException)e;
resolvableApiException.startResolutionForResult(MainActivity.this,REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException ex) {
ex.printStackTrace();
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
//Device does not have location
break;
}
}
}
});
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CHECK_SETTINGS) {
switch (resultCode) {
case Activity.RESULT_OK:
Toast.makeText(this, "GPS is tured on", Toast.LENGTH_SHORT).show();
case Activity.RESULT_CANCELED:
Toast.makeText(this, "GPS required to be tured on", Toast.LENGTH_SHORT).show();
}
}
}
}
in activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="#+id/location_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Turn On GPS"
android:textAllCaps="false"
android:textSize="16sp" />
</LinearLayout>
the source: https://github.com/Pritish-git/turnOn_location
Against the traditional approach of prompting user to go to the settings page and enable location services and come back again, I have noticed a simpler way of doing the same in some of the latest apps.
Referring to below screenshot, it prompts a dialog to user to enable the location services with just one click and it works in those apps.
How can I achieve the same?
This dialog is created by LocationSettingsRequest.Builder available in the Google Play Services.
You need to add a dependency to your app build.gradle:
compile 'com.google.android.gms:play-services-location:10.0.1'
Then you can use this minimal example:
private void displayLocationSettingsRequest(Context context) {
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).build();
googleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
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();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
Log.i(TAG, "All location settings are satisfied.");
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.");
break;
}
}
});
}
You can find the complete example here.
Follow the steps mentioned below
1) Create a LocationRequest as per your wish
LocationRequest mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000)
.setFastestInterval(1 * 1000);
2) Create a LocationSettingsRequest.Builder
LocationSettingsRequest.Builder settingsBuilder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
settingsBuilder.setAlwaysShow(true);
3) Get LocationSettingsResponse Task using following code
Task<LocationSettingsResponse> result = LocationServices.getSettingsClient(this)
.checkLocationSettings(settingsBuilder.build());
Note: LocationServices.SettingsApi is deprecated so, use SettingsClient Instead.
4) Add a OnCompleteListener to get the result from the Task.When the Task completes, the client can check the location settings by looking at the status code from the LocationSettingsResponse object.
result.addOnCompleteListener(new OnCompleteListener<LocationSettingsResponse>() {
#Override
public void onComplete(#NonNull Task<LocationSettingsResponse> task) {
try {
LocationSettingsResponse response =
task.getResult(ApiException.class);
} catch (ApiException ex) {
switch (ex.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException resolvableApiException =
(ResolvableApiException) ex;
resolvableApiException
.startResolutionForResult(MapsActivity.this,
LOCATION_SETTINGS_REQUEST);
} catch (IntentSender.SendIntentException e) {
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
}
});
CASE 1: LocationSettingsStatusCodes.RESOLUTION_REQUIRED : Location is not enabled but, we can ask the user to enable the location by prompting him to turn on the location with the dialog (by calling startResolutionForResult).
CASE 2: 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.
5) OnActivityResult we can get the user action in the location settings dialog. RESULT_OK => User turned on the Location. RESULT_CANCELLED - User declined the location setting request.
Its Working Similar to google maps
Add Dependency in build.gradle file
compile 'com.google.android.gms:play-services:8.3.0'
this or that
compile 'com.google.android.gms:play-services-location:10.0.1'
import android.content.Context;
import android.content.IntentSender;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import java.util.List;
public class LocationOnOff_Similar_To_Google_Maps extends AppCompatActivity {
protected static final String TAG = "LocationOnOff";
private GoogleApiClient googleApiClient;
final static int REQUEST_LOCATION = 199;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setFinishOnTouchOutside(true);
// Todo Location Already on ... start
final LocationManager manager = (LocationManager) LocationOnOff_Similar_To_Google_Maps.this.getSystemService(Context.LOCATION_SERVICE);
if (manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)) {
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps already enabled",Toast.LENGTH_SHORT).show();
finish();
}
// Todo Location Already on ... end
if(!hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)){
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps not Supported",Toast.LENGTH_SHORT).show();
}
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && hasGPSDevice(LocationOnOff_Similar_To_Google_Maps.this)) {
Log.e("keshav","Gps already enabled");
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps not enabled",Toast.LENGTH_SHORT).show();
enableLoc();
}else{
Log.e("keshav","Gps already enabled");
Toast.makeText(LocationOnOff_Similar_To_Google_Maps.this,"Gps already enabled",Toast.LENGTH_SHORT).show();
}
}
private boolean hasGPSDevice(Context context) {
final LocationManager mgr = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
if (mgr == null)
return false;
final List<String> providers = mgr.getAllProviders();
if (providers == null)
return false;
return providers.contains(LocationManager.GPS_PROVIDER);
}
private void enableLoc() {
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(LocationOnOff_Similar_To_Google_Maps.this)
.addApi(LocationServices.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
googleApiClient.connect();
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d("Location error","Location error " + connectionResult.getErrorCode());
}
}).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);
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();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(LocationOnOff_Similar_To_Google_Maps.this, REQUEST_LOCATION);
finish();
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
}
}
});
}
}
}
implementation 'com.google.android.gms:play-services-location:16.0.0'
Variable Declaration
private SettingsClient mSettingsClient;
private LocationSettingsRequest mLocationSettingsRequest;
private static final int REQUEST_CHECK_SETTINGS = 214;
private static final int REQUEST_ENABLE_GPS = 516;
Open Dialog Using Below Code
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(new LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY));
builder.setAlwaysShow(true);
mLocationSettingsRequest = builder.build();
mSettingsClient = LocationServices.getSettingsClient(YourActivity.this);
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
//Success Perform Task Here
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(YourActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sie) {
Log.e("GPS","Unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.e("GPS","Location settings are inadequate, and cannot be fixed here. Fix in Settings.");
}
}
})
.addOnCanceledListener(new OnCanceledListener() {
#Override
public void onCanceled() {
Log.e("GPS","checkLocationSettings -> onCanceled");
}
});
onActivityResult
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CHECK_SETTINGS) {
switch (resultCode) {
case Activity.RESULT_OK:
//Success Perform Task Here
break;
case Activity.RESULT_CANCELED:
Log.e("GPS","User denied to access location");
openGpsEnableSetting();
break;
}
} else if (requestCode == REQUEST_ENABLE_GPS) {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!isGpsEnabled) {
openGpsEnableSetting();
} else {
navigateToUser();
}
}
}
private void openGpsEnableSetting() {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, REQUEST_ENABLE_GPS);
}
Thanks to Mattia Maestrini +1
Xamarin solution:
using Android.Gms.Common.Apis;
using Android.Gms.Location;
public const int REQUEST_CHECK_SETTINGS = 0x1;
private void DisplayLocationSettingsRequest()
{
var googleApiClient = new GoogleApiClient.Builder(this).AddApi(LocationServices.API).Build();
googleApiClient.Connect();
var locationRequest = LocationRequest.Create();
locationRequest.SetPriority(LocationRequest.PriorityHighAccuracy);
locationRequest.SetInterval(10000);
locationRequest.SetFastestInterval(10000 / 2);
var builder = new LocationSettingsRequest.Builder().AddLocationRequest(locationRequest);
builder.SetAlwaysShow(true);
var result = LocationServices.SettingsApi.CheckLocationSettings(googleApiClient, builder.Build());
result.SetResultCallback((LocationSettingsResult callback) =>
{
switch (callback.Status.StatusCode)
{
case LocationSettingsStatusCodes.Success:
{
DoStuffWithLocation();
break;
}
case LocationSettingsStatusCodes.ResolutionRequired:
{
try
{
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
callback.Status.StartResolutionForResult(this, REQUEST_CHECK_SETTINGS);
}
catch (IntentSender.SendIntentException e)
{
}
break;
}
default:
{
// If all else fails, take the user to the android location settings
StartActivity(new Intent(Android.Provider.Settings.ActionLocationSourceSettings));
break;
}
}
});
}
protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data)
{
switch (requestCode)
{
case REQUEST_CHECK_SETTINGS:
{
switch (resultCode)
{
case Android.App.Result.Ok:
{
DoStuffWithLocation();
break;
}
case Android.App.Result.Canceled:
{
//No location
break;
}
}
break;
}
}
}
NOTE:
This will not work with Huawei or other devices which does not have google services installed.
Kotlin Solution
Add build.gradle(Module:app)
implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
after that create this function
fun enablegps() {
val mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(2000)
.setFastestInterval(1000)
val settingsBuilder = LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest)
settingsBuilder.setAlwaysShow(true)
val result = LocationServices.getSettingsClient(this).checkLocationSettings(settingsBuilder.build())
result.addOnCompleteListener { task ->
//getting the status code from exception
try {
task.getResult(ApiException::class.java)
} catch (ex: ApiException) {
when (ex.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
Toast.makeText(this,"GPS IS OFF",Toast.LENGTH_SHORT).show()
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
val resolvableApiException = ex as ResolvableApiException
resolvableApiException.startResolutionForResult(this,REQUEST_CHECK_SETTINGS
)
} catch (e: IntentSender.SendIntentException) {
Toast.makeText(this,"PendingIntent unable to execute request.",Toast.LENGTH_SHORT).show()
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
Toast.makeText(
this,
"Something is wrong in your GPS",
Toast.LENGTH_SHORT
).show()
}
}
}
}
}
Android Marshmallow 6 supports runtime permission. Runtime permissions only work on Marshmallow and on pre-Marshmallow it still works the old way.
You can learn more about it in this Android Developer official Video:
https://www.youtube.com/watch?v=C8lUdPVSzDk
And requesting permission: http://developer.android.com/training/permissions/requesting.html
Thank you Mattia Maestrini for the Answer, I would like to add that using
compile 'com.google.android.gms:play-services-location:8.1.0'
would suffice. This prevents your app including unnecessary libraries and helps for keeping your method count low.
With recent Marshmallow update, even when the Location setting is turned on, your app will require to explicitly ask for permission. The recommended way to do this is to show the Permissions section of your app wherein the user can toggle the permission as required. The code snippet for doing this is as below:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Location Permission");
builder.setMessage("The app needs location permissions. Please grant this permission to continue using the features of the app.");
builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.setNegativeButton(android.R.string.no, null);
builder.show();
}
} else {
// do programatically as show in the other answer
}
And override the onRequestPermissionsResult method as below:
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
}
}
}
Another approach is you can also use the SettingsApi to inquire which location provider(s) are enabled. If none is enabled, you can prompt a dialog to change the setting from within the app.
If you want to replace deprecated onActivityResult and startResolutionForResult in Fragment, see https://stackoverflow.com/a/65816646/2914140.
val checkLocationSettings =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
if (result.resultCode == RESULT_OK) {
// GPS is turned on in system settings.
}
}
...
val intentSenderRequest = IntentSenderRequest.Builder(resolvable.resolution).build()
checkLocationSettings.launch(intentSenderRequest)
private void openDeviceLocationRequest() {
if (!locationPermissionGranted)
return;
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true); //this is the key ingredient
Task<LocationSettingsResponse> result =
LocationServices.getSettingsClient(this).checkLocationSettings(builder.build());
result.addOnCompleteListener(task -> {
try {
LocationSettingsResponse response = task.getResult(ApiException.class);
// All location settings are satisfied. The client can initialize location
// requests here.
if(lastKnownLocation == null)
getDeviceLocation();
} 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(
MapAddressActivity.this,
REQUEST_CHECK_SETTINGS);
} 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;
}
}
});
}
The simplest way I found while my research, is to create a Util class for this location requesting process and then call it to turn the gps ON for us.
Please check this blog! It told the whole story.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );
LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
if (!manager.isProviderEnabled( LocationManager.GPS_PROVIDER )) {
buildAlertMessageNoGps();
}
}
private void buildAlertMessageNoGps() {
final AlertDialog.Builder builder = new AlertDialog.Builder( this );
builder.setMessage( "Your GPS seems to be disabled, do you want to enable it?" )
.setCancelable( false )
.setPositiveButton( "Yes", (dialog, id) -> startActivity( new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS ) ) )
.setNegativeButton( "No", (dialog, id) -> dialog.cancel() );
final AlertDialog alert = builder.create();
alert.show();
}