Last active
March 28, 2017 12:45
-
-
Save nissivm/b3832ecaaa5d46af2e53c60626a5efee to your computer and use it in GitHub Desktop.
Android (from Marshmallow up) - Obtain user location permission & user location
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- In your AndroidManifest.xml --> | |
<?xml version="1.0" encoding="utf-8"?> | |
<manifest | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
package="your.app.package"> | |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies { | |
... | |
compile 'com.android.support:appcompat-v7:25.3.0' | |
compile 'com.google.android.gms:play-services-location:10.2.1' | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package your.app.package; | |
import android.app.Activity; | |
import android.app.AlertDialog; | |
import android.content.Context; | |
import android.content.DialogInterface; | |
import android.content.Intent; | |
import android.content.IntentSender; | |
import android.content.SharedPreferences; | |
import android.content.pm.PackageManager; | |
import android.location.Location; | |
import android.os.Bundle; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.ActivityCompat; | |
import android.support.v4.content.ContextCompat; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.Toast; | |
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.LocationListener; | |
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.Random; | |
public class UserLocationActivity extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener | |
{ | |
private GoogleApiClient googleApiClient; | |
private LocationRequest locationRequest; | |
private static final String PREFS_NAME = "MyApp"; | |
private int googleApiClientRequestCode = 0; | |
private int locationPermissionRequestCode = 0; | |
private int locationSettingsRequestCode = 0; | |
private boolean isReturnedFromSettings = false; | |
private boolean justAskedForUserLocation = false; | |
private AlertDialog dialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) | |
{ | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.user_location_activity); | |
if (savedInstanceState != null) | |
{ | |
googleApiClientRequestCode = savedInstanceState.getInt("googleApiClientRequestCode"); | |
locationPermissionRequestCode = savedInstanceState.getInt("locationPermissionRequestCode"); | |
locationSettingsRequestCode = savedInstanceState.getInt("locationSettingsRequestCode"); | |
} | |
if (googleApiClient == null) | |
{ | |
googleApiClient = new GoogleApiClient.Builder(this) | |
.addConnectionCallbacks(this) | |
.addOnConnectionFailedListener(this) | |
.addApi(LocationServices.API) | |
.build(); | |
} | |
if (locationRequest == null) | |
{ | |
locationRequest = LocationRequest.create() | |
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) | |
.setInterval(5 * 1000) // 5 seconds, in milliseconds | |
.setFastestInterval(2 * 1000); // 2 seconds, in milliseconds | |
} | |
if (googleApiClientRequestCode == 0) | |
{ | |
Random r = new Random(); | |
int min = 1000; | |
int max = 10000; | |
googleApiClientRequestCode = r.nextInt((max - min) + 1) + min; | |
locationPermissionRequestCode = r.nextInt((max - min) + 1) + min; | |
locationSettingsRequestCode = r.nextInt((max - min) + 1) + min; | |
} | |
Button button = (Button)findViewById(R.id.allowLocationBtn); | |
button.setOnClickListener(new View.OnClickListener() | |
{ | |
@Override | |
public void onClick(View v) | |
{ | |
int permission = ContextCompat.checkSelfPermission(UserLocationActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION); | |
if (permission != PackageManager.PERMISSION_GRANTED) | |
{ | |
askLocationPermission(); | |
} | |
else | |
{ | |
checkGoogleApiClient(); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onResume() | |
{ | |
if (isReturnedFromSettings) | |
{ | |
isReturnedFromSettings = false; | |
int permission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION); | |
if (permission == PackageManager.PERMISSION_GRANTED) | |
{ | |
checkGoogleApiClient(); | |
} | |
} | |
super.onResume(); | |
} | |
@Override | |
protected void onPause() | |
{ | |
if (dialog != null) | |
{ | |
dialog.dismiss(); | |
dialog = null; | |
} | |
super.onPause(); | |
} | |
@Override | |
protected void onStop() | |
{ | |
if (googleApiClient.isConnected()) | |
{ | |
googleApiClient.disconnect(); | |
} | |
super.onStop(); | |
} | |
@Override | |
public void onSaveInstanceState(Bundle outState) | |
{ | |
outState.putInt("googleApiClientRequestCode", googleApiClientRequestCode); | |
outState.putInt("locationPermissionRequestCode", locationPermissionRequestCode); | |
outState.putInt("locationSettingsRequestCode", locationSettingsRequestCode); | |
super.onSaveInstanceState(outState); | |
} | |
//----------------------------------------------------------------------------------------// | |
// Ask location permission | |
//----------------------------------------------------------------------------------------// | |
private void askLocationPermission() | |
{ | |
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); | |
String result = settings.getString("AskedLocationPermissionFirstTime", "does not exist"); | |
if (result.equals("does not exist")) | |
{ | |
// First time app is asking for location permission. | |
SharedPreferences.Editor editor = settings.edit(); | |
editor.putString("AskedLocationPermissionFirstTime", "True"); | |
editor.apply(); | |
ActivityCompat.requestPermissions(UserLocationActivity.this, | |
new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION}, | |
locationPermissionRequestCode); | |
} | |
else if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.ACCESS_FINE_LOCATION)) | |
{ | |
// User was asked permission before, but denied. | |
// Never ask again was not checked. | |
ActivityCompat.requestPermissions(UserLocationActivity.this, | |
new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION}, | |
locationPermissionRequestCode); | |
} | |
else | |
{ | |
// Never ask again was checked. | |
takeMeThereCancelDialog(); | |
} | |
} | |
//----------------------------------------------------------------------------------------// | |
// Take me there / Cancel dialog | |
//----------------------------------------------------------------------------------------// | |
private void takeMeThereCancelDialog() | |
{ | |
DialogInterface.OnClickListener takeMeThereListener = new DialogInterface.OnClickListener() | |
{ | |
@Override | |
public void onClick(DialogInterface d, int which) | |
{ | |
isReturnedFromSettings = true; | |
dialog = null; | |
startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_SETTINGS)); | |
} | |
}; | |
DialogInterface.OnClickListener cancelListener = new DialogInterface.OnClickListener() | |
{ | |
@Override | |
public void onClick(DialogInterface d, int which) | |
{ | |
dialog = null; | |
} | |
}; | |
AlertDialog.Builder builder = new AlertDialog.Builder(UserLocationActivity.this); | |
builder.setTitle("Enable my location tracking"); | |
builder.setMessage("Just access device's settings:"); | |
builder.setCancelable(false); | |
builder.setPositiveButton("Take me there", takeMeThereListener); | |
builder.setNegativeButton("Cancel", cancelListener); | |
dialog = builder.create(); | |
dialog.setCanceledOnTouchOutside(false); | |
dialog.show(); | |
} | |
//----------------------------------------------------------------------------------------// | |
// ActivityCompat.OnRequestPermissionsResultCallback | |
//----------------------------------------------------------------------------------------// | |
@Override | |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) | |
{ | |
if (requestCode == locationPermissionRequestCode) | |
{ | |
if ((permissions.length == 1) && | |
permissions[0].equals(android.Manifest.permission.ACCESS_FINE_LOCATION) && | |
(grantResults[0] == PackageManager.PERMISSION_GRANTED)) | |
{ | |
// User gave her/his permission | |
checkGoogleApiClient(); | |
} | |
} | |
} | |
//----------------------------------------------------------------------------------------// | |
// Check Google Api Client | |
//----------------------------------------------------------------------------------------// | |
private void checkGoogleApiClient() | |
{ | |
if(googleApiClient.isConnected()) | |
{ | |
checkLocationSettings(); | |
} | |
else | |
{ | |
googleApiClient.connect(); | |
} | |
} | |
//----------------------------------------------------------------------------------------// | |
// Check location settings | |
//----------------------------------------------------------------------------------------// | |
// Note: This step is important, for example, if user doesn't have gps enabled, which is necessary for fine location | |
private void checkLocationSettings() | |
{ | |
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest); | |
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build()); | |
result.setResultCallback(new ResultCallback<LocationSettingsResult>() | |
{ | |
@Override | |
public void onResult(@NonNull LocationSettingsResult result) | |
{ | |
final Status status = result.getStatus(); | |
switch (status.getStatusCode()) | |
{ | |
case LocationSettingsStatusCodes.SUCCESS: | |
// All location settings are satisfied. | |
// The client can initialize location requests here. | |
getUserLocation(); | |
break; | |
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: | |
// 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(). | |
status.startResolutionForResult(UserLocationActivity.this, locationSettingsRequestCode); | |
} | |
catch (IntentSender.SendIntentException e) | |
{ | |
// Resolution intent has been canceled or is no longer able to execute the request. | |
Context context = getApplicationContext(); | |
int duration = Toast.LENGTH_LONG; | |
Toast toast = Toast.makeText(context, "An error occurred, please try again.", duration); | |
toast.show(); | |
} | |
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. | |
String msg = "Your device was not able to meet the necessary requirements to retrieve your location in a satisfactory manner."; | |
DialogInterface.OnClickListener okListener = new DialogInterface.OnClickListener() | |
{ | |
@Override | |
public void onClick(DialogInterface d, int which) | |
{ | |
dialog = null; | |
} | |
}; | |
AlertDialog.Builder builder = new AlertDialog.Builder(UserLocationActivity.this); | |
builder.setMessage(msg); | |
builder.setCancelable(false); | |
builder.setPositiveButton("Ok", okListener); | |
dialog = builder.create(); | |
dialog.setCanceledOnTouchOutside(false); | |
dialog.show(); | |
break; | |
} | |
} | |
}); | |
} | |
//----------------------------------------------------------------------------------------// | |
// Get user location | |
//----------------------------------------------------------------------------------------// | |
private void getUserLocation() | |
{ | |
int permission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION); | |
if (permission == PackageManager.PERMISSION_GRANTED) | |
{ | |
PendingResult<Status> result = LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this); | |
result.setResultCallback(new ResultCallback<Status>() | |
{ | |
@Override | |
public void onResult(@NonNull Status status) | |
{ | |
if (status.isSuccess()) | |
{ | |
// If in a real device, onLocationChanged(Location location) will be automatically called | |
} | |
else | |
{ | |
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, UserLocationActivity.this); | |
} | |
} | |
}); | |
} | |
} | |
//----------------------------------------------------------------------------------------// | |
// LocationListener | |
//----------------------------------------------------------------------------------------// | |
@Override | |
public void onLocationChanged(Location location) // Not called in simulator | |
{ | |
double userLat = location.getLatitude(); | |
double userLong = location.getLongitude(); | |
LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, this); | |
// Do some action with user coordinates | |
} | |
//----------------------------------------------------------------------------------------// | |
// onActivityResult | |
//----------------------------------------------------------------------------------------// | |
@Override | |
protected void onActivityResult(int requestCode, int resultCode, Intent data) | |
{ | |
if (resultCode == RESULT_OK) | |
{ | |
if (requestCode == locationSettingsRequestCode) | |
{ | |
checkLocationSettings(); | |
} | |
else if (requestCode == googleApiClientRequestCode) | |
{ | |
googleApiClient.connect(); | |
} | |
} | |
else | |
{ | |
Context context = getApplicationContext(); | |
int duration = Toast.LENGTH_LONG; | |
Toast toast = Toast.makeText(context, "An error occurred, please try again.", duration); | |
toast.show(); | |
} | |
} | |
//----------------------------------------------------------------------------------------// | |
// ConnectionCallbacks | |
//----------------------------------------------------------------------------------------// | |
@Override | |
public void onConnected(@Nullable Bundle bundle) | |
{ | |
checkLocationSettings(); | |
} | |
@Override | |
public void onConnectionSuspended(int i) {} | |
//----------------------------------------------------------------------------------------// | |
// OnConnectionFailedListener | |
//----------------------------------------------------------------------------------------// | |
@Override | |
public void onConnectionFailed(@NonNull ConnectionResult result) | |
{ | |
GoogleApiAvailability avail = GoogleApiAvailability.getInstance(); | |
int errorCode = result.getErrorCode(); | |
if (avail.isUserResolvableError(errorCode)) | |
{ | |
avail.getErrorDialog(this, errorCode, googleApiClientRequestCode).show(); | |
} | |
else | |
{ | |
Context context = getApplicationContext(); | |
int duration = Toast.LENGTH_LONG; | |
Toast toast = Toast.makeText(context, "An error occurred, please try again.", duration); | |
toast.show(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment