可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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.
回答2:
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
回答3:
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();
回答4:
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;
}
}
});
回答5:
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
}