im working on a small app that needs access to GPS so that i can track my position.
However i pasted some code that i can use to check if it works. I will rewrite it later so that it can be adjusted but for now i just want to try it.
BUT when i execute the app all paramaters stay the way they were initialized.
I do have all permissions enabled and also GPS enabled. Even went outside to check if it works, but it will always stay the same.
after the app asks if i allow the app to use gps service everything is executed correctly. It returns positive for location tracking.
Here is the code: (it can also be found under here: https://github.com/codeanticode/processing-android-tutorials/blob/master/location_permissions/ex1_gps/ex1_gps.pde)
/*****************************************************************************************
Android Processing GPS example
Query the phone's GPS and display the data on the screen
Rolf van Gelder - v 22/02/2011 - http://cage.nl :: http://cagewebdev.com :: info#cage.nl
Check the ACCESS_FINE_LOCATION permission in Sketch Permissions!
*****************************************************************************************/
// Import needed Android libs
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.provider.Settings;
import android.os.Bundle;
import android.Manifest;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
// Set up the variables for the LocationManager and LocationListener
LocationManager locationManager;
MyLocationListener locationListener;
// Variables to hold the current GPS data
float currentLatitude = 0;
float currentLongitude = 0;
float currentAccuracy = 0;
String currentProvider = "";
boolean hasLocation = false;
void setup () {
fullScreen();
orientation(PORTRAIT);
textFont(createFont("SansSerif", 26 * displayDensity));
textAlign(CENTER, CENTER);
requestPermission("android.permission.ACCESS_FINE_LOCATION", "initLocation");
}
void draw() {
background(0);
if (hasPermission("android.permission.ACCESS_FINE_LOCATION")) {
text("Latitude: " + currentLatitude + "\n" +
"Longitude: " + currentLongitude + "\n" +
"Accuracy: " + currentAccuracy + "\n" +
"Provider: " + currentProvider, 0, 0, width, height);
} else {
text("No permissions to access location", 0, 0, width, height);
}
}
void initLocation(boolean granted) {
if (granted) {
Context context = getContext();
locationListener = new MyLocationListener();
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
hasLocation = true;
} else {
hasLocation = false;
}
}
// Class for capturing the GPS data
class MyLocationListener implements LocationListener {
public void onLocationChanged(Location location) {
currentLatitude = (float)location.getLatitude();
currentLongitude = (float)location.getLongitude();
currentAccuracy = (float)location.getAccuracy();
currentProvider = location.getProvider();
}
public void onProviderDisabled (String provider) {
currentProvider = "";
}
public void onProviderEnabled (String provider) {
currentProvider = provider;
}
public void onStatusChanged (String provider, int status, Bundle extras) {
}
}
The solution:
change the "0, 0" in locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener); to a "1000, 0" depending on how often you want to get your current position in this case: 1000 ms. Im not gonna talk about the second 0.
also instead of using NETWORK_PROVIDER use GPS_PROVIDER to get your true GPS pos instead of networked pos.
Related
I'm create background service to update location. It work well with wifi in sleep mode but when i use mobile network in sleep mode, my background service not update location. What should i do to run background service with mobile network in sleep mode?
I using Service library and update location to server.
import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class LocationService extends Service {
double latitude=0f;
double longitude=0f;
private LocationManager locationManager = null;
int LOCATION_INTERVAL = 300000;
float LOCATION_DISTANCE = 0f;
public ServerHelper serverHelper = new ServerHelper();
#Override
public void onCreate() {
Log.d("onCreate: ", "create");
initializeLocationManager();
try {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
LOCATION_INTERVAL,
LOCATION_DISTANCE,
locationListeners[0]);
} catch (java.lang.SecurityException ex) {
} catch (IllegalArgumentException ex) {
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.d("onBind: ", "bind");
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("onStartCommand: ", "startcommand");
super.onStartCommand(intent,flags,startId);
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d("onDestroy: ", "destroy");
super.onDestroy();
if (locationManager != null) {
for (LocationListener locationListener : locationListeners)
{
try {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.removeUpdates(locationListener);
} catch (Exception ex) {
}
}
}
}
private class LocationListener implements
android.location.LocationListener {
Location mLocation;
Calendar calendar;
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss",
Locale.getDefault());
#Override
public void onLocationChanged(Location location) {
Log.d("onLocationChanged: ", "locationChange");
calendar = Calendar.getInstance();
Date date = calendar.getTime();
String time = dateFormat.format(date);
mLocation.set(location);
latitude = location.getLatitude();
longitude = location.getLongitude();
String latlng = latitude+","+longitude;
serverHelper.updateLocation(getApplicationContext(),latlng,time);
}
#Override
public void onStatusChanged(String provider, int status, Bundle
extras) {
Log.d("onStatusChanged: ", "status");
}
#Override
public void onProviderEnabled(String provider) {
Log.d("onProviderEnabled: ", "proEnabled");
}
#Override
public void onProviderDisabled(String provider) {
Log.d("onProviderDisabled: ", "proDisabled");
}
LocationListener(String provider) {
mLocation = new Location(provider);
}
}
LocationListener[] locationListeners = new LocationListener[] {
//new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
private void initializeLocationManager() {
if (locationManager == null) {
locationManager = (LocationManager)
getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
}
when i use mobile network in sleep mode. onLocationChanged can't call
You should not use a background service for something like that. Modern Android versions will kill the service after 15 minutes and you can't restart it unless your app is running in the foreground. Android tries to preserve battery life and you should try to support it.
Here are possible solutions:
Use AlarmManager to setup a repeating alarm. Android may decide to delay your alarm in certain situations, e.g. if the phone is sleeping.
Use JobScheduler to schedule a recurring job which updates the location. This requires Android L.
Use the Android Jetpack WorkManager. This combines the above two solutions and picks the best way under the hood. This is the preferred solution. Check this page out to see how to schedule recurring work.
If you really want to use a background service for continuously updating the location, you need to create foreground service by calling startForeground() in your service and passing a notification. This notification will be shown to the user as long as your service is running but Android won't kill it. This solution is not recommended as it drains the battery faster and the user will notice due to the ongoing notification.
The main pattern is this: don't keep your app running but schedule the location updates with one of the above solutions. Android became very restrictive with background services over the last couple of versions and forces you to adopt the new mechanics by killing your background services and not letting allow you to restart them unless your app is in the foreground. This preserves battery. I'd recommend to not update the location more than every 15 minutes.
I made a simple app with geolocation that displays current location of the user in text views, like latitude, longitude and with Geocoder cityname countryname postal-code, etc.
Everything works perfectly in the emulator but for some reason the location doesn't get retrieved in my mobile.
The emulator is running android 7.1 and my mobile is running android 7.0 but that should not be a problem because I made the app with 6.0 marshmallow in mind.
Here is the code
"Mainactivity"
package com.example.slimshady.LocationInfoApp;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
LocationManager locationManager;
LocationListener locationListener;
Geocoder geocoder;
TextView latitude, longitude, city, postcode, country;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
latitude = (TextView)findViewById(R.id.latitude);
longitude = (TextView) findViewById(R.id.longitude);
city = (TextView)findViewById(R.id.city);
postcode = (TextView)findViewById(R.id.postcode);
country = (TextView)findViewById(R.id.country);
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
updateLocationInfo(location);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
};
// asking permission starts here
if (Build.VERSION.SDK_INT < 23){
// api level lower than 23 so no need to ask for permission
try {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,0, locationListener);
}
catch (SecurityException e){
e.printStackTrace();
}
}
else {
// api level greater than or equal to 23 checking if has permission if not VVVV this condition
// means go ask for permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
}
else{
// means api level greater than or equal to 23 and already has permission
// so no need to go out and ask for permission
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,0, locationListener);
// last known location because we went to this part means we have been here before
Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKnownLocation != null) {
updateLocationInfo(lastKnownLocation);
}
}
}
// asking permission ends here
}
public void updateLocationInfo(Location location) {
geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
try {
List<Address> locationAddress = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(),1);
if (locationAddress != null && locationAddress.size() > 0) {
latitude.setText("Latitude: "+String.valueOf(locationAddress.get(0).getLatitude()));
longitude.setText("Longitude: "+String.valueOf(locationAddress.get(0).getLongitude()));
city.setText("City: "+String.valueOf(locationAddress.get(0).getLocality()));
postcode.setText("Post Code: "+String.valueOf(locationAddress.get(0).getPostalCode()));
country.setText("Country: "+String.valueOf(locationAddress.get(0).getCountryName()));
}
}
catch (Exception e){
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
startListening();
}
}
public void startListening(){
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,0, locationListener);
}
}
}
The code is simple and basic, everything should work fine but for some reason it doesn't.
I mean the GPS receiver in my physical device works with google-maps so I know its not broken.
See it works in the emulator fine
But the same code does not work on my mobile and I have added all the permissions:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET"/>
See the same app doesn't work on my physical device, this is a screenshot from my physical device
As you see the location is on and I have granted permission when asked in the popup.
And last but not least to show that the GPS receiver works and is not damaged in my physical device.
Screenshot of me using google maps
I circled in red the GPS on and that maps can get my GPS location
If you are using released apk in physical device then you have to add SHA1 for release apk in restriction section of Google API console . I think it helps .
If not, then please show your logcat error by debugging app in physical device.
There are multiple ways that your device can locate itself. These are frequently confused as "GPS" when they are not.
GPS (Global Positioning System) This is a Global Navigation Satellite System (GNSS) which relies on signals from an orbiting constellation of satellites to locate the device. GPS specifically refers to the constellation of satellites deployed by the United States Department of Defense. Alternatives include GLONASS (Russian) and Galileo (European).
Network This uses WiFi or Bluetooth signals to locate your device. The device scans for transmitters IDs, then sends those IDs to a server over its internet connection to lookup in a database. The server responds with a location.
Your code currently uses only LocationManager.GPS_PROVIDER, which uses only satellites to locate your device. Google Maps may be using Network location, which can still work when GPS is disabled.
I suspect you need to either:
Add LocationManager.NETWORK_PROVIDER
or
Enable GPS on your device. This is somewhere under Settings and Location.
I resolved issue like yours totally removed location manager, and make all location work based on FusedLocationProviderClient, also I was have some strange bug on samsung s8 with LocationSettingsRequest that can start default dialog to turn on gps, it was worked with bugs but after removing locationManager.requestLocationUpdates it works perfectlly with fused.
I wrote and compiled the program below and ran it but the intended purpose, which is to display the speed to a textView doesn't function as far as i can tell from running it on my phone.
There are two location output variables, speed, and ourSpe because ourSpe came from a youtube video I watched and it didn't work, and speed comes from a stack overflow question I looked up. Both helped but neither is getting a result to print out ass I press the Button spedButt. I think I just wrote the code in the wrong order but I'm also not sure if I'm in using LocationManager right.
The layout file only has two textViews and a Button in a Relativelayoutbut stack overflow keeps giving me an error and I can't figure that one out either. I'm having a bad day.
Main Code
package com.example.vitaliy_2.safespeedalert;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class SpeedTest extends AppCompatActivity implements LocationListener {
TextView txt;
TextView txt_2;
Button spedButt;
float curSpe;
float speed;
Location l;
Location mLastLocation;
Location pCurrentLocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_speed_test);
txt = (TextView) findViewById(R.id.speed_display);
txt_2 = (TextView) findViewById(R.id.speed_display_2);
spedButt = (Button) findViewById(R.id.spedButt);
speed = 0;
LocationManager lm = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=PackageManager.PERMISSION_GRANTED) {return;}
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.onLocationChanged(null);
}
#Override
public void onLocationChanged(final Location location) {
l = location;
if (this.mLastLocation != null)
speed = (float )Math.sqrt(
Math.pow(pCurrentLocation.getLongitude() - mLastLocation.getLongitude(), 2)
+ Math.pow(pCurrentLocation.getLatitude() - mLastLocation.getLatitude(), 2)
) / (pCurrentLocation.getTime() - this.mLastLocation.getTime());
this.mLastLocation = pCurrentLocation;
spedButt.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
if(l == null){
txt.setText("-.- m/s");
txt_2.setText("-.- m/s");
}else{
if (pCurrentLocation.hasSpeed())
speed = pCurrentLocation.getSpeed();
curSpe = location.getSpeed();
String sent = speed + "m/s";
txt.setText(sent);
String sentTwo = curSpe + "m/s";
txt_2.setText(sentTwo);
}
}
});
}
Answering My own question, This code pops up automatically but there still needs to be a clause that asks for permission.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
return;
}else{
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, this);
}
this.onLocationChanged(null);
This question is directly related to the same prevailing stackoverflow question at "Android: get current location of user without using gps or internet" where the accepted answer is actually not answering the question.
I should be able to get the current location name (eg:city name, village name) of the device via network provider not with GPS or internet.
Following is the accepted answer in that question. (The following code parts should be included in the onCreate() method)
// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
I changed the above code given in the linked answer as following but no success.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView txtView = (TextView) findViewById(R.id.tv1);
txtView.setText("ayyo samitha");
////
// Acquire a reference to the system Location Manager
LocationManager locationManager;
locationManager= (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
}
private void makeUseOfNewLocation(Location location) {
txtView.setText("sam came in");
txtView.append(location.toString());
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {
// makeUseOfNewLocation(location);
}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
}
How to accomplish what I want by correcting above code or any other method? Note that I want to get the location name, but not the longitudes and latitudes. Can somebody please help me.
What you are referring to here (showing location name on older phones) is done using "Cell Broadcast" (or "CB"). This has absolutely nothing to do with the Location API or any variations on that.
Cell towers can send out broadcast information that can be received by devices (something like "one to many SMS"). Some operators have used Cell Broadcast to broadcast the name of the location where the cell tower is. Some operators have used Cell Broadcast to broadcast the location (lat/long) of the cell tower. Some operators have used Cell Broadcast to send advertising tickers. There are no standards for the information contained in a CB broadcast message and each mobile operator can choose to use this or not.
Since most operators do not send these messages, it probably doesn't make sense to invest any time in trying to receive and decode them. But if you want to try, you can register a BroadcastReceiver listening for this Intent action: android.provider.Telephony.SMS_CB_RECEIVED. See the documentation for more details about what data is contained in the Intent.
The problem is that the code you tried does work, probably just not as well as you wished. For example, the accuracy such a method provides on Samsung Galaxy S3 is 2000m, meaning the actual position is anywhere within a circle of 2 kilometers radius. Additional it would probably take quite a large change in location before your app would be informed of a location change since the margin of error is so big.
A GPS or LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY (if Google Play Services is used) is required to get a reasonably good location. This does require android.permission.ACCESS_FINE_LOCATION, however unless you only require km level accuracy, otherwise this permission is a must.
Finally note that using Google Play Services with LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY I can get location data as accurate as 10m without turning on GPS, so this should still satisfy your requirement.
Below is a complete example:
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
MainActivity.java
import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class MainActivity extends Activity implements
com.google.android.gms.location.LocationListener, ConnectionCallbacks,
OnConnectionFailedListener {
private final FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
private GoogleApiClient mGoogleAPIClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGoogleAPIClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
}
#Override
protected void onResume() {
super.onResume();
mGoogleAPIClient.connect();
}
#Override
protected void onPause() {
super.onPause();
if (mGoogleAPIClient != null) {
mGoogleAPIClient.disconnect();
}
}
#Override
public void onConnected(Bundle arg0) {
final LocationRequest locationRequest = LocationRequest.create();
locationRequest
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
fusedLocationProviderApi.requestLocationUpdates(mGoogleAPIClient,
locationRequest, this);
}
#Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
}
#Override
public void onLocationChanged(Location location) {
// the location is no more than 10 min old, and with reasonable
// accurarcy (50m), done
if (System.currentTimeMillis() < location.getTime() + 10 * 60 * 1000
&& location.getAccuracy() < 50) {
mGoogleAPIClient.disconnect();
mGoogleAPIClient = null;
((TextView) findViewById(R.id.test)).setText(location.toString());
}
}
}
According to android docs using LocationManager is not the current recomended API (see reference):
The Google Play services location APIs are preferred over the
Android framework location APIs (android.location) as a way of
adding location awareness to your app.
To learn how to set up the Google Services client library, see Setup in the Google Play services guide.
Once you have linked Google Services client library to your app you can achieve user location using FusedLocationProviderApi:
import android.location.Location;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
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.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
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.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class MainActivity extends ActionBarActivity
implements ConnectionCallbacks, OnConnectionFailedListener {
// ..
private GoogleApiClient mGoogleAPIClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// create google api client object
mGoogleAPIClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
protected void onStart() {
super.onStart();
mGoogleAPIClient.connect();
}
#Override
protected void onStop() {
super.onStop();
mGoogleAPIClient.disconnect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this,
"Could not connect to Google Play Services",
Toast.LENGTH_SHORT).show();
finish();
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG,
"Successfuly connect to Google Play Services");
// retrieve last location once connected
Location lastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleAPIClient);
if (lastLocation == null) {
// should request new one
// location should be enabled
Log.i(TAG,
"No location data previously acquired.. should request!");
Toast.makeText(this,
"Requesting location data ..",
Toast.LENGTH_SHORT).show();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
PendingResult<Status> result = LocationServices.FusedLocationApi
.requestLocationUpdates(mGoogleAPIClient,
locationRequest,
new LocationListener() {
#Override
public void onLocationChanged(Location location) {
makeUseOfNewLocation(location);
}
});
// TODO: use result to retrieve more info
} else {
makeUseOfNewLocation(lastLocation);
}
}
#Override
public void onConnectionSuspended(int i) {
}
private void makeUseOfNewLocation(Location location) {
// do your stuff here
}
I have tested the code above and it works without internet connection but it requires that user enable location feature on device. Also it requires that the user have already enabled Location History feature into location feature.
Hope that this helps you.
You can try getting a country level accuracy using the Locale object or using the Telephony service. No internet or GPS required.
Getting country code from Locale:
String locale = context.getResources().getConfiguration().locale.getCountry();
Getting country code from Android's Telephony service:
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
// Will work on all networks. Only provide the SIM card's country
String countryCode = tm.getSimCountryIso();
// Might not work well on CDMA networks. Will provide the country code
// for the country the device is currently in.
String currentCountryCode = tm.getNetworkCountryIso();
Better code samples and discussion here.
Good luck with this. It's called geocoder. Or more specifically reverse geocoding to turn coordinates into a human readable output. I'm fairly sure the one google provides is a pay service but you get a bunch free. So plan on caching the results and using your cached results when ever possible.
List<Address> list = geoCoder.getFromLocation(location
.getLatitude(), location.getLongitude(), 1);
if (list != null & list.size() > 0) {
Address address = list.get(0);
result = address.getLocality();
return result;
https://developer.android.com/training/location/display-address.html
How to get city name from latitude and longitude coordinates in Google Maps?
try this code..
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
public class AppLocationService extends Service implements LocationListener {
protected LocationManager locationManager;
Location location;
private static final long MIN_DISTANCE_FOR_UPDATE = 10;
private static final long MIN_TIME_FOR_UPDATE = 1000 * 60 * 2;
public AppLocationService(Context context) {
locationManager = (LocationManager) context
.getSystemService(LOCATION_SERVICE);
}
public Location getLocation(String provider) {
if (locationManager.isProviderEnabled(provider)) {
locationManager.requestLocationUpdates(provider,
MIN_TIME_FOR_UPDATE, MIN_DISTANCE_FOR_UPDATE, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(provider);
return location;
}
}
return null;
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
and next class is
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class AndroidLocationActivity extends Activity {
Button btnGPSShowLocation;
Button btnNWShowLocation;
AppLocationService appLocationService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
appLocationService = new AppLocationService(
AndroidLocationActivity.this);
btnGPSShowLocation = (Button) findViewById(R.id.btnGPSShowLocation);
btnGPSShowLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Location gpsLocation = appLocationService
.getLocation(LocationManager.GPS_PROVIDER);
if (gpsLocation != null) {
double latitude = gpsLocation.getLatitude();
double longitude = gpsLocation.getLongitude();
Toast.makeText(
getApplicationContext(),
"Mobile Location (GPS): \nLatitude: " + latitude
+ "\nLongitude: " + longitude,
Toast.LENGTH_LONG).show();
} else {
showSettingsAlert("GPS");
}
}
});
btnNWShowLocation = (Button) findViewById(R.id.btnNWShowLocation);
btnNWShowLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Location nwLocation = appLocationService
.getLocation(LocationManager.NETWORK_PROVIDER);
if (nwLocation != null) {
double latitude = nwLocation.getLatitude();
double longitude = nwLocation.getLongitude();
Toast.makeText(
getApplicationContext(),
"Mobile Location (NW): \nLatitude: " + latitude
+ "\nLongitude: " + longitude,
Toast.LENGTH_LONG).show();
} else {
showSettingsAlert("NETWORK");
}
}
});
}
public void showSettingsAlert(String provider) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(
AndroidLocationActivity.this);
alertDialog.setTitle(provider + " SETTINGS");
alertDialog
.setMessage(provider + " is not enabled! Want to go to settings menu?");
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
AndroidLocationActivity.this.startActivity(intent);
}
});
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertDialog.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
and this user permission given At Manifest File
<!-- to get location using GPS -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- to get location using NetworkProvider -->
<uses-permission android:name="android.permission.INTERNET" />
I am not using mock locations for this... In fact the code was working fine just last week.
I have an app that gathers GPS data and spits out a google maps link using X,Y coordinates generated by the application itself. I am not 100% sure why its not working the way it should be but when I request the app to make a google maps link based on the GPS location provided by the phone it tells me I am 5 - 6 blocks away from my point of origin (Where I actually am at the time) Not quite what I want it to do
Knowns:
I have the proper permissions set up
All of the code worked last week just fine
Here is the code to gather the GPS info:
Toast.makeText(context, "Gathering GPS Data...", Toast.LENGTH_SHORT).show();
gps = new gpsTracker(Settings.this);
if(gps.canGetLocation()){
try{
gps.getLocation();
lon = gps.getLongitude();
lat = gps.getLatitude();
Toast.makeText(getApplicationContext(), "Your location is - \nlat: " + lat + "\nlon: " + lon, Toast.LENGTH_LONG).show();
}
catch(Exception e){}
}
else{
gps.showSettingsAlert();
}
The class all of the above is pulling from:
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;
import android.util.Log;
public class gpsTracker extends Service implements LocationListener {
private final Context mContext;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute
// Declaring a Location Manager
protected LocationManager locationManager;
public gpsTracker(Context context) {
this.mContext = context;
getLocation();
}
public Location getLocation() {
try {
locationManager = (LocationManager) mContext
.getSystemService(LOCATION_SERVICE);
// getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// getting network status
isNetworkEnabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
// no network provider is enabled
} else {
this.canGetLocation = true;
// First get location from Network Provider
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("Network", "Network");
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("GPS Enabled", "GPS Enabled");
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return location;
}
/**
* Stop using GPS listener
* Calling this function will stop using GPS in your app
* */
public void stopUsingGPS(){
if(locationManager != null){
locationManager.removeUpdates(gpsTracker.this);
}
}
/**
* Function to get latitude
* */
public double getLatitude(){
if(location != null){
latitude = location.getLatitude();
}
// return latitude
return latitude;
}
/**
* Function to get longitude
* */
public double getLongitude(){
if(location != null){
longitude = location.getLongitude();
}
// return longitude
return longitude;
}
/**
* Function to check GPS/wifi enabled
* #return boolean
* */
public boolean canGetLocation() {
return this.canGetLocation;
}
/**
* Function to show settings alert dialog
* On pressing Settings button will lauch Settings Options
* */
public void showSettingsAlert(){
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();
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
From what is specified[difference of 4-5 blocks], you may be obtaining the location from networkProvider only.
With this gpsTracker code mentioned in the question,
there are a few modifications required, instead of using the code as it is:
1.
There are 2 if loops which verify the source of location is enabled or not and No 'else':
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("Network", "Network");
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("GPS Enabled", "GPS Enabled");
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
This means the application is going to do twice the work when you can obtain the location from both sources. Further, the source of location obtained always remains ambiguous.
This is good when you just need approximate location which should not be null majorly.
If you want to use only this class to obtain location, try structuring the if-else according to requirement and ensuring that its not going to repeat if the location is obtained.
Eg. if GPS is on a higher preference, applies in your case, shift that if above and put the network condition with an else like:
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("GPS Enabled", "GPS Enabled");
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
} else if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
Log.d("Network", "Network");
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
For your requirement, i suggest removing the network provider part and obtaining the location only from GPS, esp if line of sight is not a problem.
When your code was working fine, it must be fetching the location from GPS and setting it in the object. But because of the two "if" and no "else", you'l never know whether location obtained is from Network or GPS - you can check location.getProvider() inside the condition of canGetLocation()
2.
Also, you can log the message or prompt some action for one particular source...like:
In this part:
if (!isGPSEnabled && !isNetworkEnabled) {
// no network provider is enabled
}
just separate it into two different if(s) and code accordingly. As of now, nothing happens here so you wouldn't know if both are disabled unless you check it externally.
Suggestion: Try the LocationClient which uses GooglePlayServices for Retrieving Current Location . I have found it more reliable and useful. Check this Fused Location Provider example, setting LocationRequest object according to your requirement is the key.
Another update: just came across: useful ques on stack overflow - Good way of getting the users location
Update for anybody looking up this question/answer
Regarding the suggestion of LocationClient;
LocationClient is no longer found under com.google.android.gms.location, refer:
Android play services 6.5: LocationClient is missing
You should check out http://developer.android.com/guide/topics/location/strategies.html. There are some nice strategies to obtain accurate locations on this page. Here is some example code I've take from the site:
private static final int TWO_MINUTES = 1000 * 60 * 2;
/** Determines whether one Location reading is better than the current Location fix
* #param location The new Location that you want to evaluate
* #param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}