android - GPS app crashes on location update request - android

I have tried to follow a tutorial to the fullest. Even tried to make few changes. I admit I am very new to Android. Pardon the n00b and unprepared question.
This app crashes as soon as I open. I have tried to comment the updateGPS() call. Which made the app open but crashes again if I touch the "Location Updates" (sw_locationsupdates) switch which calls updateGPS().
`
tv_lat = findViewById(R.id.tv_lat);
tv_lon = findViewById(R.id.tv_lon);
tv_address = findViewById(R.id.tv_address);
tv_altitude = findViewById(R.id.tv_altitude);
tv_accuracy = findViewById(R.id.tv_accuracy);
tv_speed = findViewById(R.id.tv_speed);
tv_sensor = findViewById(R.id.tv_sensor);
tv_updates = findViewById(R.id.tv_updates);
tv_address = findViewById(R.id.tv_address);
sw_locationsupdates = findViewById(R.id.sw_locationsupdates);
sw_gps = findViewById(R.id.sw_gps);
locationRequest = new LocationRequest();
locationRequest.setInterval(1000 * DEFAULT_UPDATE_INTERVAL);
locationRequest.setFastestInterval(1000 * FAST_UPDATE_INTERVAL);
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
locationCallBack = new LocationCallback() {
#Override
public void onLocationResult(#NonNull LocationResult locationResult) {
super.onLocationResult(locationResult);
// save the location
updateUIValues(Objects.requireNonNull(locationResult.getLastLocation()));
}
};
sw_gps.setOnClickListener(new View.OnClickListener() {
#SuppressLint("SetTextI18n")
#Override
public void onClick(View v) {
if (sw_gps.isChecked()) {
// most accurate - use GPS
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
tv_sensor.setText("Using GPS sensors");
}
else {
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
tv_sensor.setText("Using Towers + WiFi");
}
}
});
sw_locationsupdates.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View w) {
if(sw_locationsupdates.isChecked()) {
// turn on lcation tracking
startLocationUpdates();
}
else {
// turn off tracking
stopLocationUpdates();
}
}
});
updateGPS(); // tried to comment this.
} //end of onCreate method
#SuppressLint("SetTextI18n")
private void startLocationUpdates() {
tv_updates.setText("Location is being tracked");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fsdLocationProviderClient.requestLocationUpdates(locationRequest, locationCallBack, null);
updateGPS();
}
}
#SuppressLint("SetTextI18n")
private void stopLocationUpdates() {
tv_updates.setText("Location is NOT being tracked");
tv_lat.setText("Not tracking location");
tv_lon.setText("Not tracking location");
tv_speed.setText("Not tracking location");
tv_address.setText("Not tracking location");
tv_accuracy.setText("Not tracking location");
tv_sensor.setText("Not tracking location");
fsdLocationProviderClient.removeLocationUpdates(locationCallBack);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_FINE_LOCATION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
updateGPS();
}
else {
Toast.makeText(this, "This app requires permission to be granted to function", Toast.LENGTH_SHORT).show();
finish();
}
break;
}
}
private void updateGPS () {
// get permission from user to track GPS
// get the current location from the fused API
// update the UI - i.e set all properties in their associated text view items
fsdLocationProviderClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// user provided the permission
fsdLocationProviderClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// we got permission. Put the values of location, into the UI components.
updateUIValues(location);
}
});
} else {
// permission required
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_FINE_LOCATION);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
#SuppressLint("SetTextI18n")
private void updateUIValues(Location location) {
// update all of the text view objects with a new location
tv_lat.setText(String.valueOf(location.getLatitude()));
tv_lon.setText(String.valueOf(location.getLongitude()));
tv_accuracy.setText(String.valueOf(location.getAccuracy()));
if (location.hasAltitude()) {
tv_altitude.setText(String.valueOf(location.getAltitude()));
}
else {
tv_altitude.setText("Not available");
}
if (location.hasSpeed()) {
tv_speed.setText(String.valueOf(location.getAltitude()));
}
else {
tv_speed.setText("Not available");
}
Geocoder geocoder = new Geocoder(MainActivity.this);
try {
List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
tv_address.setText(addresses.get(0).getAddressLine(0));
}
catch (Exception e) {
tv_address.setText("Unable to get street address");
}
}
}
`
I am following this youtube video.
Android Studio Tutorial - Build a GPS App
build.gradle has
implementation 'com.google.android.gms:play-services-location:21.0.0
AndroidManifest.xml has
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Tried to use
locationRequest = new LocationRequest.Builder();
LocationRequest.Builder.setIntervalMillis(Priority.PRIORITY_PASSIVE);
LocationRequest.Builder.setMinUpdateIntervalMillis(Priority.PRIORITY_HIGH_ACCURACY);
LocationRequest.Builder.setPriority(Priority.PRIORITY_BALANCED_POWER_ACCURACY);
Didn't get very far.
Tried to use Try and catch updateGPS(). No luck

Related

How to ask every time for permission on activity start if the permission is not granted or denied previously

I am working on an android app that needs user location, every time user logins into the app.
I have written code to get user location and works fine, but the problem is if the user denies permission twice it didn't ask again, here is my code:
public class MainActivity extends AppCompatActivity {
String myLocation = "";
private LocationRequest locationRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(2000);
getCurrentLocation();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (isGPSEnabled()) {
getCurrentLocation();
} else {
turnOnGPS();
}
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2) {
if (resultCode == Activity.RESULT_OK) {
getCurrentLocation();
}
}
}
private void getCurrentLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (isGPSEnabled()) {
LocationServices.getFusedLocationProviderClient(MainActivity.this)
.requestLocationUpdates(locationRequest, new LocationCallback() {
#Override
public void onLocationResult(#NonNull LocationResult locationResult) {
super.onLocationResult(locationResult);
LocationServices.getFusedLocationProviderClient(MainActivity.this)
.removeLocationUpdates(this);
if (locationResult != null && locationResult.getLocations().size() > 0) {
int index = locationResult.getLocations().size() - 1;
double latitude = locationResult.getLocations().get(index).getLatitude();
double longitude = locationResult.getLocations().get(index).getLongitude();
myLocation = "Latitude: " + latitude + " Longitude: " + longitude;
Toast.makeText(getApplicationContext(), myLocation, Toast.LENGTH_LONG).show();
}
}
}, Looper.getMainLooper());
} else {
turnOnGPS();
}
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
}
}
private void turnOnGPS() {
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, 2);
} catch (IntentSender.SendIntentException ex) {
ex.printStackTrace();
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
//Device does not have location
break;
}
}
}
});
}
private boolean isGPSEnabled() {
LocationManager locationManager = null;
boolean isEnabled = false;
if (locationManager == null) {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
isEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
return isEnabled;
}
}
As, the user's location is mandatory for the working of app. Now, I want the app to:
1- ask for permission on activity start, if the permission is not granted or denied previously.
2- if permission is granted then proceed further else close the activity.
So, how can I achieve this.
Thanks
You can check whether the user has given permission or not using checkSelfPermission and if not then you ask for permission again else process with program flow.
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED){
doStuff()
} else {
requestStoragePermission()
}
but the problem is if the user denies permission twice it didn't ask
again,
Yes, you cannot ask again once the user denies the permission with "Don't ask again" checked. This checkbox is normally checked by default on the second permission request. Beware that on api 11, there is no checkbox and the denial is automatic auto-denial auto-reset.
The way is that, you don't assume something about it, just put logic for handling it. If denied, you can only inform the user about the required permission. The official doc says: ref
If the ContextCompat.checkSelfPermission() method returns
PERMISSION_DENIED, call shouldShowRequestPermissionRationale(). If
this method returns true, show an educational UI to the user. In this
UI, describe why the feature, which the user wants to enable, needs a
particular permission.
info

Request runtime permissions on android

I am trying to get runtime permissions on my app. However the app is not displaying the dialog to request the specific permission. The code below only works when the GPS is turned on on the phone manually.
I am running the app on Android 5.0.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_location = findViewById(R.id.get_location);
txt_latitude = findViewById(R.id.latitude);
txt_longitude = findViewById(R.id.longitude);
txt_timestamp = findViewById(R.id.timestamp);
btn_map = findViewById(R.id.map);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
btn_location.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getLocation();
}
});
}
private void getLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_FINE_LOCATION
}, REQUEST_LOCATION_PERMISSION);
} else {
mFusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener < Location > () {
#Override
public void onSuccess(Location location) {
if (location != null) {
mLastLocation = location;
txt_latitude.setText(getString(R.string.location_latitude, mLastLocation.getLatitude()));
txt_longitude.setText(getString(R.string.location_longitude, mLastLocation.getLongitude()));
txt_timestamp.setText(getString(R.string.timestamp, mLastLocation.getTime()));
} else {
txt_latitude.setText(R.string.no_latitude);
txt_longitude.setText(R.string.no_longitude);
txt_timestamp.setText(R.string.no_timestamp);
}
}
});
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLocation();
} else {
Toast.makeText(this, R.string.location_permission_denied, Toast.LENGTH_SHORT).show();
}
}
}
}
Since you are run on Android 5.0 the Android runtime permission won't be shown. As runtime permission is only be shown starting from Android 6 (Marshmellow).
Please check the official documentation for the runtime permission details.

How can I get continuous location updates in Android like in Google Maps?

I'm building a friend tracking android app. While my friend activated the app and goes away along with his GPS and cellular data on, I need to track him on my device. That's the concept.
I've implemented LocationListener class and now I can get the last updated location either from Gps or Network but is not updated unless I launch Google Maps and return to my application. After googling, I learned that location cache is updated only by GMaps.!
Is there an alternate way to continuously update location?
What if when I need to get continues location after the device locked without making use of Wakelock?
This is my location listener class:
package com.amazinginside;
/** AMAZING LOCATION SUPPORT CLASS, Devoloped By SANGEETH NANDAKUMAR */
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
public class AmazingLocation extends Service implements LocationListener
{
private final Context mContext;
boolean isGPSEnabled = false;
boolean isNetworkEnabled = false;
boolean canGetLocation = false;
Location location;
double latitude=0.0;
double longitude=0.0;
//MINIMUM DISTANCE FOR UPDATE (meters)
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 0 Meters
//MINIMUM TIME BETWEEN UPDATES
private static final long MIN_TIME_BW_UPDATES = 1000 * 0; // 0 Seconds
//LOCATION MANAGER
protected LocationManager locationManager;
//CONSTRUCTOR
public AmazingLocation(Context context)
{
this.mContext = context;
getLocation();
}
//LOCATION PROVISION
public Location getLocation()
{
try
{
//GET LOCATION MANAGER
locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
//CHECK GPS STATE
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
//CHECK NETWORK STATE
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled)
{
//NO LOCATION PROVIDERS
}
else
{
this.canGetLocation = true;
/** GET LOCATION FROM NETWORK */
//FIRST GET LOCATION FROM NETWORK
if (isNetworkEnabled)
{
//REQUEST LOCATION
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null)
{
//START WITH LAST KNOWN LOCATION
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//EXTRACT LOCATION
if (location != null)
{
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
/** GET LOCATION FROM GPS SENSOR */
//THEN GET LOCATION FROM GPS
if (isGPSEnabled)
{
if (location == null)
{
//REQUEST GPS LOCATION
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null)
{
//EXTRACT LAST KNOWN LOCATION
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
//RETURN LOCATION
if (location != null)
{
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return location;
}
//STOP GPS SENSOR
public void stopUsingGPS()
{
if(locationManager != null)
{
locationManager.removeUpdates(AmazingLocation.this);
}
}
//EXTRACT LATTITUDE
public double getLatitude()
{
if(location != null)
{
latitude = location.getLatitude();
}
// return latitude
return latitude;
}
//EXTACT LONGITUDE
public double getLongitude()
{
if(location != null)
{
longitude = location.getLongitude();
}
// return longitude
return longitude;
}
//CAN I GET THE LOCATION.?
public AmazingStatus canGetLocation()
{
AmazingStatus status=new AmazingStatus();
if(this.canGetLocation)
{
status.setStatus(true);
status.setErrorcode(0);
status.setErrormsg("Task completed");
}
else
{
status.setStatus(false);
status.setErrorcode(145);
status.setErrormsg("Please turn on GPS access manually");
}
return status;
}
//SHOW LOCATION SETTINGS
public AmazingStatus showSettingsAlert()
{
final AmazingStatus status=new AmazingStatus();
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
alertDialog.setTitle("REQUIRES LOCATION ACCESS");
alertDialog.setMessage("Please allow GPS access to this app");
//POSSITIVE REPLY
alertDialog.setPositiveButton("Allow", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog,int which)
{
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
status.setStatus(true);
status.setErrorcode(0);
status.setErrormsg("Task completed");
}
});
//NEGATIVE REPLY
alertDialog.setNegativeButton("Deny", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
status.setStatus(false);
status.setErrorcode(408);
status.setErrormsg("User denied permission");
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
return status;
}
//UNUSED OVERRIDE METHORDS...
#Override
public void onLocationChanged(Location location)
{
getLocation();
}
#Override
public void onProviderDisabled(String provider)
{
}
#Override
public void onProviderEnabled(String provider)
{
getLocation();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
getLocation();
}
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
}
This my onCreate() method:
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//CREATE A BUTTON HANDLER
Button start_btn=(Button)findViewById(R.id.start_location_streaming);
//ON BUTTON CLICK EVENT
start_btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//REPEAT A METHORD AT SPECIFIC INTERVALS
Timer myTimer = new Timer();
myTimer.schedule(new TimerTask()
{
#Override
public void run()
{
TimerMethod();
}
}, 0, 8000);
}
}); }
These are other methods:
private void TimerMethod()
{
//START METHORD
this.runOnUiThread(Timer_Tick);
}
//LOCATION REPORTING METHORD
private Runnable Timer_Tick = new Runnable()
{
public void run()
{
Toast.makeText(MainActivity.this, "Current latitude : "+Double.toString(getLocation().latitude), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "Current longitude : "+Double.toString(getLocation().longitude), Toast.LENGTH_SHORT).show();
}
};
private LatLng getLocation()
{
//CREATE A LOCATION CLASS INSTANCE
AmazingLocation gps = new AmazingLocation(this);
//RETRIVE LOCATION
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();
//RETURN LOCATION
LatLng loc=new LatLng(latitude,longitude);
return loc;
}
Now the problem is, the toast just shows previously known the location and not updating unless I opened Google Maps and returned.
Any help will be great for me.
Use Fused location provider in Android set your interval in that:
For an example create your activity like this:
public class LocationActivity extends Activity implements
LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "LocationActivity";
private static final long INTERVAL = 1000 * 10;
private static final long FASTEST_INTERVAL = 1000 * 5;
Button btnFusedLocation;
TextView tvLocation;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
String mLastUpdateTime;
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate ...............................");
//show error dialog if GoolglePlayServices not available
if (!isGooglePlayServicesAvailable()) {
finish();
}
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
setContentView(R.layout.activity_main);
tvLocation = (TextView) findViewById(R.id.tvLocation);
btnFusedLocation = (Button) findViewById(R.id.btnShowLocation);
btnFusedLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
updateUI();
}
});
}
#Override
public void onStart() {
super.onStart();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
Log.d(TAG, "Location update resumed .....................");
}
}
#Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop fired ..............");
mGoogleApiClient.disconnect();
Log.d(TAG, "isConnected ...............: " + mGoogleApiClient.isConnected());
}
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
return false;
}
}
#Override
public void onConnected(Bundle bundle) {
Log.d(TAG, "onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
startLocationUpdates();
}
protected void startLocationUpdates() {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
Log.d(TAG, "Location update started ..............: ");
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "Connection failed: " + connectionResult.toString());
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "Firing onLocationChanged..............................................");
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
updateUI();
}
private void updateUI() {
Log.d(TAG, "UI update initiated .............");
if (null != mCurrentLocation) {
String lat = String.valueOf(mCurrentLocation.getLatitude());
String lng = String.valueOf(mCurrentLocation.getLongitude());
tvLocation.setText("At Time: " + mLastUpdateTime + "\n" +
"Latitude: " + lat + "\n" +
"Longitude: " + lng + "\n" +
"Accuracy: " + mCurrentLocation.getAccuracy() + "\n" +
"Provider: " + mCurrentLocation.getProvider());
} else {
Log.d(TAG, "location is null ...............");
}
}
#Override
protected void onPause() {
super.onPause();
stopLocationUpdates();
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
Log.d(TAG, "Location update stopped .......................");
}
#Override
public void onResume() {
super.onResume();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
Log.d(TAG, "Location update resumed .....................");
}
}
}
Google play services required:
To get continiuos location update, you can refer to the above provided answers .
But You can also make use of LocationServices which is faster than other approaches and much easy and efficient to get location.
This approach is quit long but kindly follow all the provided steps
So let me provide a brief working :
Add these two dependencies in your gradle app file
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.android.gms:play-services-location:17.0.0'
Add these permissions in the manifest file outside applicationtag
Declare variable outside onCreate
private FusedLocationProviderClient fusedLocationClient;
private LocationRequest mLocationRequest;
private LocationCallback mlocationCallback;
private LocationSettingsRequest.Builder builder;
private static final int REQUEST_CHECK_SETTINGS = 102;
Now inside onCreate :
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
fetchLastLocation();
mlocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
// Update UI with location data
// ...
Log.e("CONTINIOUSLOC: ", location.toString());
}
};
};
mLocationRequest = createLocationRequest();
builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
checkLocationSetting(builder);
No define fetchLastLocation method
private void fetchLastLocation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// Activity#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for Activity#requestPermissions for more details.
// Toast.makeText(MainActivity.this, "Permission not granted, Kindly allow permission", Toast.LENGTH_LONG).show();
showPermissionAlert();
return;
}
}
fusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener() {
#Override
public void onSuccess(Location location) {
// Got last known location. In some rare situations this can be null.
if (location != null) {
// Logic to handle location object
Log.e("LAST LOCATION: ", location.toString()); // You will get your last location here
}
}
});
}
Now define other two method for permission request
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case 123: {
// If request is cancelled, the result arrays are empty.
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// permission was denied, show alert to explain permission
showPermissionAlert();
}else{
//permission is granted now start a background service
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fetchLastLocation();
}
}
}
}
}
private void showPermissionAlert(){
if (ActivityCompat.checkSelfPermission(MainHomeActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(MainHomeActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainHomeActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 123);
}
}
now define createLocationRequest method and checkLocationSetting method :
protected LocationRequest createLocationRequest() {
LocationRequest mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(30000);
mLocationRequest.setFastestInterval(10000);
mLocationRequest.setSmallestDisplacement(30);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
return mLocationRequest;
}
private void checkLocationSetting(LocationSettingsRequest.Builder builder) {
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
startLocationUpdates();
return;
}
});
task.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull final Exception e) {
if (e instanceof ResolvableApiException) {
// Location settings are not satisfied, but this can be fixed
AlertDialog.Builder builder1 = new AlertDialog.Builder(mContext);
builder1.setTitle("Continious Location Request");
builder1.setMessage("This request is essential to get location update continiously");
builder1.create();
builder1.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ResolvableApiException resolvable = (ResolvableApiException) e;
try {
resolvable.startResolutionForResult(MainHomeActivity.this,
REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e1) {
e1.printStackTrace();
}
}
});
builder1.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(mContext, "Location update permission not granted", Toast.LENGTH_LONG).show();
}
});
builder1.show();
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == REQUEST_CHECK_SETTINGS) {
if (resultCode == RESULT_OK) {
// All location settings are satisfied. The client can initialize
// location requests here.
startLocationUpdates();
}
else {
checkLocationSetting(builder);
}
}
}
now atlast define startLocationUpdates and stopLocationUpdates method :
public void startLocationUpdates() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// Activity#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for Activity#requestPermissions for more details.
return;
}
}
fusedLocationClient.requestLocationUpdates(mLocationRequest,
mlocationCallback,
null /* Looper */);
}
private void stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(mlocationCallback);
}
Note : Replace context with your class context and call stopLocationUpdates() inside onDestroy method of your class
Note : For any futher information or doubt you can refer to :
https://developer.android.com/training/location/retrieve-current
https://developer.android.com/training/location/change-location-settings
https://developer.android.com/training/location/receive-location-updates
You will get your location in Logcat.
Hope this will hope you or somebody else !
I believe rather than reinventing the wheel, you can use one of the third party libraries that are easy to implement and in this case, battery efficient. One of the library I found is SmartLocation. You can add the following dependency in your build.gradle (app) to start using the library.
compile 'io.nlopez.smartlocation:library:3.2.9'
After adding the dependency, you should rebuild the project to get the references.
As an example you can try the following code in your Activity.
Button start_btn=(Button)findViewById(R.id.start_location_streaming);
Context context = start_btn.getContext();
Handler handler = new Handler();
start_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SmartLocation.with(context).location().start(locationListener);
}
});
OnLocationUpdatedListener locationListener = new OnLocationUpdatedListener({
#Override
public void onLocationUpdated(Location location) {
double lat = location.getLatitude();
double lng = location.getLongitude();
handler.postDelayed(locationRunnable,8000);
}
});
Runnable locationRunnable = new Runnable({
#Override
public void run() {
SmartLocation.with(context).location().start(locationListener);
}
});
You can stop location tracking in onStop() method
#Override
public void onStop() {
SmartLocation.with(context).location().stop();
super.onStop();
}
SmartLocation library will give you more than what is expected, just try that once.
Note: Make sure your application does have ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION (both) to have accurate results. Don't forget to ask for permissions at runtime for Android 6.0 and above.
You should use android services, rather than the app itself. This way you will achieve to run code continuously in the background and you will receive the location even if the app closes.
https://www.tutorialspoint.com/android/android_services.htm

How to get user's current location in Android

I want to fetch user's current lat long on click of a button. I know that you can get the last known location using FusedLocationApi. But what I am not able to understand is, gps or location services needs to be turned on for this? If yes, how to check that the user has turned on location and get the current location. Also, how to include marshmallow permission checks in getting the location.
I have already referred:
1) googlesamples/android-play-location
2) googlesamples/android-XYZTouristAttractions
and many other links but unable to make a complete flow.
Code
public class AccessLocationFragment extends BaseFragment implements View.OnClickListener, LocationListener,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, GeneralDialogFragment.GeneralDialogClickListener {
private static final int MY_PERMISSIONS_REQUEST_LOCATION = 101;
private static final String TAG = AccessLocationFragment.class.getSimpleName();
private static final int REQUEST_CHECK_SETTINGS = 102;
private Button mAccessLocation;
private EditText mZipCode;
private Dialog progressDialog;
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
public static AccessLocationFragment newInstance() {
return new AccessLocationFragment();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_access_location, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
RecycleApplication.getEventBus().register(this);
mAccessLocation = (Button) view.findViewById(R.id.access_location);
mZipCode = (EditText) view.findViewById(R.id.zip_code);
mAccessLocation.setOnClickListener(this);
mZipCode.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
String zipCode = mZipCode.getText().toString().trim();
if (TextUtils.isEmpty(zipCode)) {
Toast.makeText(mActivity, "Please enter zip code", Toast.LENGTH_SHORT).show();
} else {
Call<Address> response = mRecycleService.getAddress(zipCode);
response.enqueue(new GetLocationCallback(AccessLocationFragment.this));
}
}
return false;
}
});
// Create an instance of GoogleAPIClient.
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
if (!LocationUtils.checkFineLocationPermission(mActivity)) {
// See if user has denied permission in the past
if (shouldShowRequestPermissionRationale(android.Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show a simple snackbar explaining the request instead
showPermissionSnackbar();
} else {
requestFineLocationPermission();
}
} else {
displayLocationSettingsRequest();
}
}
private void startHomeActivity(Address address) {
RecyclePreferences.getInstance().setCity(address.getCity());
RecyclePreferences.getInstance().setState(address.getState());
RecyclePreferences.getInstance().setLatitude(address.getLatitude());
RecyclePreferences.getInstance().setLongitude(address.getLongitude());
RecyclePreferences.getInstance().setZipCode(address.getZipCode());
startActivity(new Intent(mActivity, HomeActivity.class));
mActivity.finish();
}
#Override
public void onSuccess(Call<Address> call, Response<Address> response) {
mActivity.hideProgressDialog(progressDialog);
if (response.isSuccessful()) {
Address address = response.body();
startHomeActivity(address);
}
}
#Override
public void onFailure(Call<Address> call, Throwable t) {
mActivity.hideProgressDialog(progressDialog);
}
#Override
public void onClick(View view) {
if (view.getId() == R.id.access_location) {
fetchAddress(mLastLocation);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
displayLocationSettingsRequest();
}
}
}
}
private void fetchAddress(Location location) {
mRecycleService = new RecycleRetrofitBuilder(mActivity).getService();
Call<Address> response = mRecycleService.getAddress(String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));
progressDialog = mActivity.showProgressDialog(mActivity);
response.enqueue(new GetLocationCallback(AccessLocationFragment.this));
}
private void requestFineLocationPermission() {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
}
private void showPermissionSnackbar() {
GeneralDialogFragment generalDialogFragment = GeneralDialogFragment.
newInstance("Permissions", "Allow Recycle the World to use your location.", "Allow", "Go Back", this);
mActivity.showDialogFragment(generalDialogFragment);
displayLocationSettingsRequest();
}
private void displayLocationSettingsRequest() {
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(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:
getLocation();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to upgrade location settings ");
try {
status.startResolutionForResult(mActivity, 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;
}
}
});
}
private void getLocation() {
if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CHECK_SETTINGS) {
getLocation();
}
}
#Override
public void onStart() {
mGoogleApiClient.connect();
super.onStart();
}
#Override
public void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
getLocation();
}
#Override
public void onDestroy() {
super.onDestroy();
RecycleApplication.getEventBus().unregister(this);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onOk(DialogFragment dialogFragment) {
dialogFragment.dismiss();
requestFineLocationPermission();
}
#Override
public void onCancel(DialogFragment dialogFragment) {
dialogFragment.dismiss();
}
}
Sorry, I haven't go through your code, I am just writing the functions that you have asked for in your question.
First, you need to build a connection to google api client like:
private synchronized void buildGoogleApiClient(){
mGoogleApiClient = new GoogleApiClient.Builder(GTApplication.getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
After this in my experience, you almost always get called onConnected() function where you can ask for the location permission after API level 23:
public void checkLocationPermission(){
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
// You don't have the permission you need to request it
ActivityCompat.requestPermissions(this, Manifest.permission.ACCESS_FINE_LOCATION), REQ_CODE);
}else{
// You have the permission.
requestLocationAccess();
}
}
If you requested the permission your onRequestPermissionsResult() function will be called with the REQ_CODE. If you need more info to implement the events check the original documentation for runtime permissions it is very useful.
When you have the permission you can check if the location is enabled like:
public void requestLocationAccess(){
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval((long) (LocationHelper.UPDATE_INTERVAL_IN_MILLISECONDS*1.1));
mLocationRequest.setFastestInterval(LocationHelper.UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
final LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true); //this is the key ingredient
com.google.android.gms.common.api.PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>(){
#Override
public void onResult(#NonNull LocationSettingsResult result){
if(requester != null){
final Status resultStatus = result.getStatus();
switch(resultStatus.getStatusCode()){
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. You can ask for the user's location HERE
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user a dialog.
try{
resultStatus.startResolutionForResult(this, REQUEST_LOCATION);
break;
}catch(IntentSender.SendIntentException ignored){}
}
}
}
}
});
}
If the enable location dialog needed to be shown to the user you will get a callback in onActivityResult() function with the request code REQUEST_LOCATION)
That's it after you done with all this process you can call locationManager.getLastKnownLocation() or start location request or whatever you want.
PS.: I have cut this code from my bigger class, so please if you find any mistakes feel free to ask. I have specified only the case when everything goes well, because it contains the essence, you can handle the exceptions yourself I hope.
try this code:
public void showMap() {
mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map);
if (map == null) {
map = mapFragment.getMap();
}
// Enable Zoom
map.getUiSettings().setZoomGesturesEnabled(true);
//set Map TYPE
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//enable Current location Button
map.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager)getActivity().getSystemService(getActivity().LOCATION_SERVICE);
Criteria criteria = new Criteria();
String bestProvider = locationManager.getBestProvider(criteria, true);
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
Location location = locationManager.getLastKnownLocation(bestProvider);
if (location != null) {
onLocationChanged(location);
}
locationManager.requestLocationUpdates(bestProvider, 2000, 0, this);
}
#Override
public void onLocationChanged(Location location) {
latitude= location.getLatitude();
longitude=location.getLongitude();
LatLng loc = new LatLng(latitude, longitude);
if (marker!=null){
marker.remove();
}
marker= map.addMarker(new MarkerOptions().position(loc).title("Sparx IT Solutions"));
map.moveCamera(CameraUpdateFactory.newLatLng(loc));
map.animateCamera(CameraUpdateFactory.newLatLngZoom(loc, 16.0f));
}
#Override
public void onProviderDisabled(String provider) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
Toast.makeText(getActivity().getBaseContext(), "Gps is turned off!!",
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(getActivity().getBaseContext(), "Gps is turned on!! ",
Toast.LENGTH_SHORT).show();
}

Android Marshmallow getLastLocation / LocationListeners not working

I have an app which gets the users current location and then loads a Google Map and plots markers of interest in their area. It works flawlessly on everything below Marshmallow. I've added the run-time permissions check, and they are being set as I do get the prompt, and after I hit accept I see the Permission listed in the app details from the settings of the phone. However, I can not for the life of me figure out why I'm getting no location back.
I am using the example as seen here https://developer.android.com/training/location/retrieve-current.html
I have all the permissions set with the tag in the manifest. I even have my Fragment implementing the LocationListener. However, the onLocationChanged method never gets called. I am calling it within the onConnected method of the Google API Client like below..
#Override
public void onConnected(#Nullable Bundle bundle) {
try {
Log.d("MYAPPTAG","isConnected: " + mGoogleApiClient.isConnected());
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
myLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
} catch (SecurityException ex) {
myLocation = null;
}
}
the onConnected method DOES get called because I get my Log to the console. myLocation is always null though. I get a message in the console everytime I call getLastLocation that says
No Location to return for getLastLocation()
GoogleSignatureVerifier: com.myappname.android signature not valid. Found: LONG KEY HERE
Is there something special I need to do in Marshmallow?
my OnLocationChanged method
#Override
public void onLocationChanged(Location location) {
myLocation = location;
Log.d("MYAPPTAG", "LocatinChngListner, loc: " + location.getLatitude() + "," + location.getLongitude());
}
AndroidManifest.xml - permissions section (above node)
<!--- App permissions -->
<permission android:name="com.myappname.android.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
<uses-permission android:name="com.myappname.android.permission.MAPS_RECEIVE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.myappname.android.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.myappname.android.permission.C2D_MESSAGE"/>
onCreate Method snippet
createLocationRequest();
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
createLocationRequest method
private void createLocationRequest(){
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(1000);
}
onStart() onStop() methods
#Override
public void onStart() {
if (!mGoogleApiClient.isConnected()) mGoogleApiClient.connect();
super.onStart();
}
#Override
public void onStop() {
if (mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect();
super.onStop();
}
I call this code below right after the Fragment onCreate method
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1 && (ContextCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
requestPermissions(new String[] { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION }, REQUEST_PERMISSION_USER_LOCATION);
} else {
googleMapsLocationPermissionContainer.setVisibility(View.GONE);
getUserLocationAndInitializeMap();
}
googleMapsLocationPermissionContainer is just a layout I overlay on the map until the permissions are granted.
getUserLocationAndInitializeMap()
try {
MapsInitializer.initialize(getActivity());
// Set reference for map object
if (map == null) {
mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
// Here I set the map to invisible then after I plot all the markers I set it to visible again
mapFragment.getView().setVisibility(View.INVISIBLE);
}
} catch (Exception e) {
// Show the google maps alert dialog
showGoogleMapsErrorDialog();
}
My approach for this is the following:
#Override
public void onResume() {
super.onResume();
initGpsTracker();
}
public synchronized void initGpsTracker() {
if (mMap != null) {
try {
checkIfPermissionAllowedForLocation();
} catch (SecurityException secex) {
Toast.makeText(getActivity(), "not enabled in manifest", Toast.LENGTH_SHORT).show();
}
}
}
/**
* rule is the following. First we check if the permissions are there. If not, we check if we can enable or not.
* If the permissions are check if gps is enabled.
*/
private void checkIfPermissionAllowedForLocation() {
//if permissions are set then we go to else, check for gps
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// Request missing location permission.
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) {
askIfToRequestPermissions();
} else {
requestPermissions();
}
} else {
// Location permission has been granted, continue as usual.
if (!isGpsProviderEnabled()) {
askToEnableGPS();
} else {
mMap.setMyLocationEnabled(true);
}
}
}
private void askToEnableGPS() {
CustomFragmentDialog customFragmentDialog = CustomFragmentDialog.newInstance(getString(R.string.enable_gps_title),
getString(R.string.enable_gps_message),
getString(R.string.ok),
getString(R.string.cancel),
callback);
customFragmentDialog.show(getFragmentManager(), CUSTOM_TAG);
}
private void requestPermissions() {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_CODE_LOCATION);
}
private void enableGPS() {
if (enableLocationService != null) {
enableLocationService.askToEnableGps(locationCallback);
}
}
private GoogleAskToEnableLocationService.GpsCallback locationCallback = new GoogleAskToEnableLocationService.GpsCallback() {
#Override
public void onSuccess() {
initGpsTracker();
}
#Override
public void onResolutionRequired(Status status) {
try {
status.startResolutionForResult(getActivity(), CONNECTION_RESOLUTION_CODE);
} catch (IntentSender.SendIntentException setex) {
Toast.makeText(getActivity(), "Exception in sending intent:", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onError() {
Toast.makeText(getActivity(), "Location services unavailable!", Toast.LENGTH_SHORT).show();
}
};
private void askIfToRequestPermissions() {
CustomFragmentDialog customFragmentDialog = CustomFragmentDialog.newInstance(getString(R.string.enable_gps_title),
getString(R.string.enable_permissions_message),
getString(R.string.ok),
getString(R.string.cancel),
callback_permissions);
customFragmentDialog.show(getFragmentManager(), CUSTOM_TAG);
}
private CustomFragmentDialog.Callback callback = new CustomFragmentDialog.Callback() {
#Override
public void onPositiveButtonClicked(Bundle bundle) {
enableGPS();
}
#Override
public void onNegativeButtonClicked(Bundle bundle) {
}
};
private CustomFragmentDialog.Callback callback_permissions = new CustomFragmentDialog.Callback() {
#Override
public void onPositiveButtonClicked(Bundle bundle) {
requestPermissions();
}
#Override
public void onNegativeButtonClicked(Bundle bundle) {
}
};
private boolean isGpsProviderEnabled() {
return googleUtils.isGpsProviderEnabled();
}
//inside it is a normal check if locationManager can access
//the gps provider
if (locationManager.getProvider(provider) == null) {
return false;
}
Now, for request permission there are some callbacks:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CONNECTION_RESOLUTION_CODE:
switch (resultCode) {
case Activity.RESULT_OK:
initGpsTracker();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getContext(), "Gps not enabled:", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
break;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE_LOCATION) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initGpsTracker();
} else {
Toast.makeText(getActivity(), "Manifest permission, not enabled", Toast.LENGTH_SHORT).show();
}
}
}
Now, finally the class where you deal with the request for the location so you do not have to go to settings:
public void askToEnableGps(final GpsCallback callback) {
if (locationClient == null) {
return;
}
mLocationRequestHighAccuracy = LocationRequest.create();
mLocationRequestHighAccuracy.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequestHighAccuracy.setInterval(30 * 1000);
mLocationRequestHighAccuracy.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequestHighAccuracy);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(locationClient, builder.build());
result.setResultCallback(getResultCallback(callback));
}
private ResultCallback<LocationSettingsResult> getResultCallback(final GpsCallback callback) {
return new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
if (result != null) {
final Status status = result.getStatus();
if (callback != null) {
//final LocationSettingsStates statesResult = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
callback.onSuccess();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
callback.onResolutionRequired(status);
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.
callback.onError();
break;
}
}
}
}
};
}
public interface GpsCallback {
/**
* callback method for when the result it is a success.
*/
void onSuccess();
/**
* callback for when user interaction it is required.
*
* #param status the result from the service needed for the resolution.
*/
void onResolutionRequired(Status status);
/**
* Callback for when the change it is not possible.
*/
void onError();
}

Categories

Resources