I'm trying to make a trivial application in which the user clicks a button and a few text views display various information about the phone(model,battery %,location,signal strength etc). I'm having trouble getting the current latitude and longitude, since when I press the button the textview displays the previous latitude/longitude(first time it shows 0,0 and the second the position I was when I first pressed it).
What I'm trying to achieve is when I press the button, activate the location manager and location listener, and make the onClick() method wait until the latitude is not equal to the old latitude. I've tried Threads, handler, and asynctask but I haven't managed anything. Any tips? This is how my onClick() method looks right now: (Infogatherer is a class where I collect all the info)
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
switch(arg0.getId()){
case R.id.bMeasurements:
oldLat=InfoGatherer.getLatitude();
oldLong=InfoGatherer.getLongitude();
//SOMEWHERE HERE START A THREAD OR SOMETHING IN ORDER TO RETRIEVE CURRENT LOCATION
//Retrieval and Assignment of information to the corresponding text fields
DeviceName.setText(infogatherer.getDeviceName());
NetworkOp.setText(infogatherer.getNetworkOp());
Date.setText(infogatherer.getDate());
BatteryStatus.setText(String.valueOf(infogatherer.getBatteryStatus()));
Generation.setText(String.valueOf(infogatherer.getGeneration()));
infogatherer.getLocation();
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
infogatherer.getSignalStrength();
SignalStrength.setText(String.valueOf(infogatherer.getDbm()));
oldLat = InfoGatherer.getLatitude();
oldLong = InfoGatherer.getLongitude();
break;
}
This is my InfoGatherer class:
package com.example.netmap;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.telephony.CellInfoGsm;
import android.telephony.CellSignalStrengthGsm;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
public class InfoGatherer extends Application{
String address,city,country;
int cid,lac,generation=0,ipAddress=0,signalStrngth=0;
private GsmCellLocation location;
private WifiInfo wifiInfo;
private LocationManager lm;
private LocationListener ll;
Geocoder geoc;
static public double Longitude,Latitude=0;
List<Address> addresses;
Context context;
Intent batteryIntent;
TelephonyManager tm;
WifiManager wifimanager;
public InfoGatherer(){
}
public InfoGatherer(Context context){
this.context = context;
}
public String getDate(){
Calendar c = Calendar.getInstance();
return Integer.toString(c.get(Calendar.DAY_OF_MONTH))+"-"+Integer.toString(c.get(Calendar.MONTH))+"-"+Integer.toString(c.get(Calendar.YEAR))+" "+Integer.toString(c.get(Calendar.HOUR_OF_DAY))+":"+Integer.toString(c.get(Calendar.MINUTE))+":"+Integer.toString(c.get(Calendar.SECOND));
}
public String getDeviceName(){
return Build.MANUFACTURER +" "+Build.MODEL;
}
public String getNetworkOp(){
tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getNetworkOperatorName();
}
public float getBatteryStatus() {
batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return ((float)batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) / (float)batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)) * 100.0f;
}
public int getGeneration(){
tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getNetworkType();
}
public int getCid(){
tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
location = (GsmCellLocation)tm.getCellLocation();
return location.getCid();
}
public int getLac(){
tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
location = (GsmCellLocation)tm.getCellLocation();
return location.getLac();
}
public String getIpAddress() {
// TODO Auto-generated method stub
wifimanager = (WifiManager) context.getSystemService(WIFI_SERVICE);
wifiInfo = wifimanager.getConnectionInfo();
ipAddress = wifiInfo.getIpAddress();
return String.format("%d.%d.%d.%d",(ipAddress & 0xff),(ipAddress >> 8 & 0xff),(ipAddress >> 16 & 0xff),(ipAddress >> 24 & 0xff));
}
public void getLocation(){
/*Criteria c = new Criteria();
c.setAccuracy(Criteria.ACCURACY_FINE);
c.setPowerRequirement(Criteria.POWER_LOW);
String provider = lm.getBestProvider(c, true);*/
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
ll = new mylocationlistener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);
}
public class mylocationlistener implements LocationListener{
#Override
public void onLocationChanged(android.location.Location location) {
// TODO Auto-generated method stub
if(location!=null){
Longitude = location.getLongitude();
Latitude = location.getLatitude();
lm.removeUpdates(ll);
}
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
//Pass views as parameters? DIscuss
//DeviceName.setText(String.valueOf(Latitude) +" "+String.valueOf(Longitude));
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
// TODO Auto-generated method stub
}
}
public void getSignalStrength(){
tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener Listener = new phoneStateListener();
tm.listen(Listener ,PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
public class phoneStateListener extends PhoneStateListener{
public void onSignalStrengthsChanged(SignalStrength signalStrength){
super.onSignalStrengthsChanged(signalStrength);
if (signalStrength.isGsm()) {
signalStrngth = -113 + 2 * signalStrength.getGsmSignalStrength();
}
else
signalStrngth = -113 + 2 * signalStrength.getCdmaDbm();
}
}
static public double getLatitude(){
return Latitude;
}
static public double getLongitude(){
return Longitude;
}
public String getAddress(){
return address;
}
public String getCity(){
return city;
}
public String getCountry(){
return country;
}
public int getDbm(){
return signalStrngth;
}
}
You don´t provide enough time to Location service get the location.
You ask for latitude and longitude before the LocationManager have time to call onLocationChanged.
infogatherer.getLocation();
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
Call infogatherer.getLocation(); out of onClick event. Do that at Activity onResume() event.
Remove lm.removeUpdates(ll); from onLocationChanged. Call it at Activity onPause()event.
If you want see this example how to create a GPS Manager Class
EDIT
Try something like this: Note: Not tested!
private void updateLocationText(double oldLat, double oldLong) {
Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
boolean isPositionChanged = false;
double lat;
double long;
while (!isPositionChanged) {
lat = InfoGatherer.getLatitude();
long = InfoGatherer.getLongitude();
if(lat != oldLat || long != oldLong)isPositionChanged = true;
}
handler.post(new Runnable(){
public void run() {
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
});
}
}
};
new Thread(runnable).start();
}
Note that if you click on the button without having been no change of location, it will run forever.
EDIT AGAIN
Another approach more clean:
Replace
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
with this
Location.postDelayed(new Runnable() {
#Override
public void run() {
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
Location.postInvalidate();//Try without, may be not necessary
}
}, 3000);//Change if need
Create the LocationListener out of Aplication.
In the Ativity instantiate the class, override the onLocationChanged event and update Location TextView there.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
.........
.........
lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
listener = new MyLocationListener(){
#Override
public void onLocationChanged(android.location.Location location) {
if(location!=null){
Location.setText(String.valueOf(location.getLatitude()+","+location.getLatitude()));
lm.removeUpdates(listener);
}
}
}
}
In onClick() event replace:
infogatherer.getLocation();
Location.setText(String.valueOf(InfoGatherer.getLatitude()+","+InfoGatherer.getLatitude()));
with
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
In the end I used AsyncTask, which helped me in order to sleep the app while I looked for the location.
private class LocationThread extends AsyncTask<Context, Void, Void> {
protected void onPreExecute() {
infogatherer.startLocationListener();
}
#Override
protected Void doInBackground(Context... params) {
while (!infogatherer.getGo()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
protected void onPostExecute(final Void unused) {
//Do whatever you wanna do after you get location
}
}
getGo is a boolean which whenever becomes true gives the location back
public class mylocationlistener implements LocationListener {
#Override
public void onLocationChanged(android.location.Location location) {
if(location != null){
Longitude = location.getLongitude();
Latitude = location.getLatitude();
lm.removeUpdates(ll);
go = true;
}
}
hope you understand the procedure. Cheers.
Related
My professor has a program that I am trying to help hime upgrade, unfortunately I am extremely new to Android. It a program that is supposed to grab your Android's location and periodically send it to a server (about every 5 seconds). But after upgrading it to use API 21 (it was on 10-14), it will only return my location as 0.0. Does anyone know what might have caused this?
Here is the Main
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.location.LocationManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
protected Button panic;
protected Button track;
private TextView latText;
private TextView lngText;
private TextView addressText;
private boolean panicking;
private boolean tracking;
protected Context mContext;
private Timer locTimer;
private final String TAG = "MainActivity";
protected Sender send;
private int trackingOn;
private int trackingOff;
private int panicOn;
private int panicOff;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tracking = false;
panicking = false;
//colors
trackingOff = Color.rgb(100, 255, 100);
trackingOn = Color.rgb(255, 255, 100);
panicOff = Color.rgb(255, 50, 50);
panicOn = Color.rgb(255, 127, 0);
setupSender();
setupView();
//createGPS();
checkGPS();
//create GPS service
Intent trackIntent = new Intent(MainActivity.this, TrackingService.class);
startService(trackIntent);
createTimer();
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public void onDestroy()
{
locTimer.cancel();
super.onDestroy();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK)
{
Log.d(TAG, "Back pressed");
//create dialog to turn off GPS
//if not then ask the user to turn it on
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Would you like to turn off the GPS?");
builder.setCancelable(false);
//yes
builder.setPositiveButton("Disable GPS in device settings", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
Intent callGPSSettingIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(callGPSSettingIntent);
finish();
}
});
//no
builder.setNegativeButton("No", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
finish();
}
});
AlertDialog gpsAlert = builder.create();
gpsAlert.show();
}
return super.onKeyDown(keyCode, event);
}
private void setupSender()
{
//get MAC address
WifiManager wifiMan = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInf = wifiMan.getConnectionInfo();
String macAddr = wifiInf.getMacAddress();
//get phone Number
TelephonyManager teleMan = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String phoneNumber = teleMan.getLine1Number();
Log.d(TAG, "My mac: " + macAddr + " My number: " + phoneNumber);
send = new Sender(macAddr, phoneNumber);
}
private class SendTracking extends AsyncTask<String, String, String>
{
#Override
protected String doInBackground(String... arg0)
{
send.sendTrack(Values.lat, Values.lng, Values.myAddress, Values.acc);
return null;
}
}
private class SendPanic extends AsyncTask<String, String, String>
{
#Override
protected String doInBackground(String... arg0)
{
send.sendPanic(Values.lat, Values.lng, Values.myAddress, Values.acc);
return null;
}
}
private void setupView()
{
latText = (TextView)findViewById(R.id.lattitude);
lngText = (TextView)findViewById(R.id.longitude);
addressText = (TextView)findViewById(R.id.address);
// create tracking button
track = (Button)findViewById(R.id.trackMe);
track.setBackgroundColor(trackingOff);
track.setOnClickListener(new OnClickListener()
{
public void onClick(View arg0)
{
tracking = !tracking;
Log.w(TAG, "Tracking button pressed");
if(tracking)
{
track.setBackgroundColor(trackingOn);
track.setText(getResources().getString(R.string.stopTrack));
Values.interval = Values.TRACK_INTERVAL; //set it so it sends right away
}
else
{
new SendTracking().execute();
track.setBackgroundColor(trackingOff);
track.setText(getResources().getString(R.string.tracker));
}
}
});
// create panic button
panic = (Button) findViewById(R.id.panic);
panic.setBackgroundColor(panicOff);
panic.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
Log.w(TAG, "Panic Pressed");
panicking = !panicking;
//send.sendPanic(Values.lat, Values.lng, Values.myAddress, Values.acc);
if(panicking)
{
panic.setBackgroundColor(panicOn);
panic.setText(getResources().getString(R.string.stopPanic));
Values.interval = Values.TRACK_INTERVAL; //set it so it sends right away
}
else
{
panic.setBackgroundColor(panicOff);
panic.setText(getResources().getString(R.string.panic));
}
}
});
}
private void createTimer()
{
//decimal formatter
final DecimalFormat format = new DecimalFormat("#.###");
// create runnable for timer
final Runnable updateLoc = new Runnable()
{
#Override
public void run()
{
Log.i(TAG, "Updating loc");
latText.setText("" + format.format(Values.lat));
lngText.setText("" + format.format(Values.lng));
addressText.setText(Values.myAddress);
//send to DB if tracking is on and enough time has passed since last update
if(tracking)
{
if (Values.interval >= Values.TRACK_INTERVAL)
{
new SendTracking().execute();
Values.interval = 0;
}
else
{
Values.interval++;
}
}
else if(panicking)
{
if (Values.interval >= Values.TRACK_INTERVAL)
{
new SendPanic().execute();
Values.interval = 0;
}
else
{
Values.interval++;
}
}
}
};
// create timer that will check for location
locTimer = new Timer("LocTimer");
locTimer.scheduleAtFixedRate(new TimerTask()
{
#Override
public void run()
{
runOnUiThread(updateLoc);
}
}, Values.UPDATE_TIMER / 2, Values.UPDATE_TIMER);
}
private void checkGPS()
{
LocationManager manager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
//check to see if GPS is enabled
if(!manager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
//if not then ask the user to turn it on
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("GPS is currently disabled. Please turn it on");
builder.setCancelable(false);
//yes
builder.setPositiveButton("Enabled GPS in device settings", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
Intent callGPSSettingIntent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(callGPSSettingIntent);
}
});
//no
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.cancel();
}
});
AlertDialog gpsAlert = builder.create();
gpsAlert.show();
}
}
}
And this is the Tracking Service
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
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.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
public class TrackingService extends Service {
private LocationManager manager;
private LocationListener listener;
private final String TAG = "TrackingService";
public class LocalBinder extends Binder {
TrackingService getService() {
return TrackingService.this;
}
}
public IBinder onBind(Intent arg0) {
return new LocalBinder();
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
public void onStart(Intent intent, int startId) {
Log.d(TAG, "Starting service");
this.onStart(intent, startId);
}
public void onCreate() {
Log.d(TAG, "Creating service");
this.createGPS();
}
public void onDestroy() {
Log.d(TAG, "Killing service");
manager.removeUpdates(listener);
super.onDestroy();
}
private LocationManager createGPS() {
// create GPS service
manager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
//context
final Context context = this;
// make listener
listener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "GPS udpate");
Values.lat = location.getLatitude();
Values.lng = location.getLongitude();
Values.acc = location.getAccuracy();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Geocoder.isPresent()) {
// Since the geocoding API is synchronous and may take a while. You don't want to lock
// up the UI thread. Invoking reverse geocoding in an AsyncTask.
(new ReverseGeocodingTask(context)).execute(new Location[]{location});
}
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
// register listener
manager.requestLocationUpdates(LocationManager.GPS_PROVIDER, Values.UPDATE_TIMER, 10f, listener);
manager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Values.UPDATE_TIMER, 10f, listener);
return manager;
}
// AsyncTask encapsulating the reverse-geocoding API. Since the geocoder API is blocked,
// we do not want to invoke it from the UI thread.
private class ReverseGeocodingTask extends AsyncTask<Location, Void, Void>
{
Context mContext;
public ReverseGeocodingTask(Context context)
{
super();
mContext = context;
}
#Override
protected Void doInBackground(Location... params)
{
Geocoder geocoder = new Geocoder(mContext, Locale.getDefault());
Location loc = params[0];
List<Address> addresses = null;
try
{
// Call the synchronous getFromLocation() method by passing in the lat/long values.
addresses = geocoder.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);
}
catch (IOException e)
{
e.printStackTrace();
// Update UI field with the exception.
//Message.obtain(mHandler, UPDATE_ADDRESS, e.toString()).sendToTarget();
Log.e("ReverseGeoCoder", "error: " + e.toString());
}
if (addresses != null && addresses.size() > 0)
{
Address address = addresses.get(0);
// Format the first line of address (if available), city, and country name.
String addressText = String.format("%s, %s, %s",
address.getMaxAddressLineIndex() > 0 ? address.getAddressLine(0) : "",
address.getLocality(),
address.getCountryName());
// Update the UI via a message handler.
//Message.obtain(mHandler, UPDATE_ADDRESS, addressText).sendToTarget();
Log.d("ReverseGeoCoder", "address: " + addressText);
Values.myAddress = addressText;
}
return null;
}
}
}
It worked just fine before, I've seen the tracking logs, but now it only returns 0.0.
My app has two activities that need GPS, so I tried to offload it to a separate class that either activity could use. I found an answer here that looked easy enough
Android - Best way to implement LocationListener across multiple activities
But of course, it's not working for me. I was wondering if anyone can see the issue. I used pretty much exactly the same code, but I got rid of the gps settings dialog.
Here's my GPS class
package fieldlayout.skipmorrow.com.fieldlayout;
import android.app.Activity;
import android.content.Context;
import android.location.LocationManager;
import android.os.Bundle;
import android.location.LocationListener;
import android.location.Location;
import android.util.Log;
/**
* Created by skip on 4/20/2015.
*/
public class GPS {
private IGPSActivity main;
// Helper for GPS-Position
private LocationListener mlocListener;
private LocationManager mlocManager;
private boolean isRunning;
public GPS(IGPSActivity main) {
this.main = main;
// GPS Position
mlocManager = (LocationManager) ((Activity) this.main).getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
// GPS Position END
this.isRunning = true;
Log.i("FieldLayout_GPS", "GPS Object created");
}
public void stopGPS() {
if(isRunning) {
mlocManager.removeUpdates(mlocListener);
this.isRunning = false;
}
Log.i("FieldLayout_GPS", "stopGPS");
}
public void resumeGPS() {
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
this.isRunning = true;
Log.i("FieldLayout_GPS", "resumeGPS");
}
public boolean isRunning() {
return this.isRunning;
}
public class MyLocationListener implements LocationListener {
private final String TAG = MyLocationListener.class.getSimpleName();
#Override
public void onLocationChanged(Location loc) {
GPS.this.main.locationChanged(loc.getLongitude(), loc.getLatitude());
Log.i("FieldLayout_GPS", "onLocationChanged");
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.i("FieldLayout_GPS", "onStatusChanged");
}
#Override
public void onProviderEnabled(String provider) {
Log.i("FieldLayout_GPS", "onProviderEnabled");
}
#Override
public void onProviderDisabled(String provider) {
Log.i("FieldLayout_GPS", "onProviderDisabled");
}
}
}
The interface file
package fieldlayout.skipmorrow.com.fieldlayout;
/**
* Created by skip on 4/20/2015.
*/
public interface IGPSActivity {
public void locationChanged(double longitude, double latitude);
}
And my implementation from my activity
package fieldlayout.skipmorrow.com.fieldlayout;
import android.content.Context;
import android.content.Intent;
public class StartActivity extends ActionBarActivity implements IGPSActivity{
private Location currentLocation;
private GPS gps;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
gps = new GPS(this);
}
#Override
protected void onResume() {
if (!gps.isRunning()) gps.resumeGPS();
super.onResume();
}
#Override
protected void onStop() {
// Disconnecting the client invalidates it.
Log.i("FieldLayout_StartAct", "onStop called. Disconnecting GPS client");
gps.stopGPS();
super.onStop();
}
#Override
public void locationChanged(double longitude, double latitude) {
Log.i("FieldLayout_StartAct", "locationChanged");
currentLocation.setLatitude(latitude);
currentLocation.setLongitude(longitude);
}
}
The only log I am seeing is the creation of the GPS object. None of the other methods in the listener are being executed.
GPS class constructor contains this row:
public GPS(IGPSActivity main) {
this.main = main;
// GPS Position
mlocManager = (LocationManager) ((Activity) this.main).getSystemService(Context.LOCATION_SERVICE);
...
}
And your interface looks like this:
public interface IGPSActivity {
public void locationChanged(double longitude, double latitude);
}
So, the GPS class get an interface, and you want to cast it into an Activity to get a system service from it. That is not going to work.
Change your GPS class a little bit. For example:
public GPS(IGPSActivity main, Activity activity){
mlocManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
...
}
Call this in your activity:
gps = new GPS(this, this);
I would like to know how to get the speed of a vehicle using your phone while seated in the vehicle using gps. I have read that the accelerometer is not very accurate. Another thing is; will GPS be accessible while seated in a vehicle. Won't it have the same effect as while you are in a building?
Here is some code I have tried but I have used the NETWORK PROVIDER instead.I will appreciate the help. Thanks...
package com.example.speedtest;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
LocationManager locManager;
LocationListener li;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
locManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
li=new speed();
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, li);
}
class speed implements LocationListener{
#Override
public void onLocationChanged(Location loc) {
Float thespeed=loc.getSpeed();
Toast.makeText(MainActivity.this,String.valueOf(thespeed), Toast.LENGTH_LONG).show();
}
#Override
public void onProviderDisabled(String arg0) {}
#Override
public void onProviderEnabled(String arg0) {}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
}
}
for more information onCalculate Speed from GPS Location Change in Android Mobile Device view this link
Mainly there are two ways to calculate the speed from mobile phone.
Calculate speed from Accelerometer
Calculate speed from GPS Technology
Unlike Accelerometer from GPS Technology if you're going to calculate speed you must enable data connection and GPS connection.
In here we are going to calculate speed using GPS connection.
In this method we using how frequency the GPS Location points are changing during single time period. Then if we have the real distance between the geo locations points we can get the speed. Because we have the distance and the time.
Speed = distance/time
But getting the distance between two location points is not very easy. Because the world is a goal in shape the distance between two geo points is different from place to place and angle to angle. So we have to use “Haversine Algorithm”
First we have to give permission for Get Location data in Manifest file
Make the GUI
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/txtCurrentSpeed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="000.0 miles/hour"
android:textAppearance="?android:attr/textAppearanceLarge" />
<CheckBox android:id="#+id/chkMetricUnits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Use metric units?"/>
Then make an interface to get the speed
package com.isuru.speedometer;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
public interface IBaseGpsListener extends LocationListener, GpsStatus.Listener {
public void onLocationChanged(Location location);
public void onProviderDisabled(String provider);
public void onProviderEnabled(String provider);
public void onStatusChanged(String provider, int status, Bundle extras);
public void onGpsStatusChanged(int event);
}
Implement the logic to get the speed using the GPS Location
import android.location.Location;
public class CLocation extends Location {
private boolean bUseMetricUnits = false;
public CLocation(Location location)
{
this(location, true);
}
public CLocation(Location location, boolean bUseMetricUnits) {
// TODO Auto-generated constructor stub
super(location);
this.bUseMetricUnits = bUseMetricUnits;
}
public boolean getUseMetricUnits()
{
return this.bUseMetricUnits;
}
public void setUseMetricunits(boolean bUseMetricUntis)
{
this.bUseMetricUnits = bUseMetricUntis;
}
#Override
public float distanceTo(Location dest) {
// TODO Auto-generated method stub
float nDistance = super.distanceTo(dest);
if(!this.getUseMetricUnits())
{
//Convert meters to feet
nDistance = nDistance * 3.28083989501312f;
}
return nDistance;
}
#Override
public float getAccuracy() {
// TODO Auto-generated method stub
float nAccuracy = super.getAccuracy();
if(!this.getUseMetricUnits())
{
//Convert meters to feet
nAccuracy = nAccuracy * 3.28083989501312f;
}
return nAccuracy;
}
#Override
public double getAltitude() {
// TODO Auto-generated method stub
double nAltitude = super.getAltitude();
if(!this.getUseMetricUnits())
{
//Convert meters to feet
nAltitude = nAltitude * 3.28083989501312d;
}
return nAltitude;
}
#Override
public float getSpeed() {
// TODO Auto-generated method stub
float nSpeed = super.getSpeed() * 3.6f;
if(!this.getUseMetricUnits())
{
//Convert meters/second to miles/hour
nSpeed = nSpeed * 2.2369362920544f/3.6f;
}
return nSpeed;
}
}
Combine logic to GUI
import java.util.Formatter;
import java.util.Locale;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
public class MainActivity extends Activity implements IBaseGpsListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.updateSpeed(null);
CheckBox chkUseMetricUntis = (CheckBox) this.findViewById(R.id.chkMetricUnits);
chkUseMetricUntis.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
MainActivity.this.updateSpeed(null);
}
});
}
public void finish()
{
super.finish();
System.exit(0);
}
private void updateSpeed(CLocation location) {
// TODO Auto-generated method stub
float nCurrentSpeed = 0;
if(location != null)
{
location.setUseMetricunits(this.useMetricUnits());
nCurrentSpeed = location.getSpeed();
}
Formatter fmt = new Formatter(new StringBuilder());
fmt.format(Locale.US, "%5.1f", nCurrentSpeed);
String strCurrentSpeed = fmt.toString();
strCurrentSpeed = strCurrentSpeed.replace(' ', '0');
String strUnits = "miles/hour";
if(this.useMetricUnits())
{
strUnits = "meters/second";
}
TextView txtCurrentSpeed = (TextView) this.findViewById(R.id.txtCurrentSpeed);
txtCurrentSpeed.setText(strCurrentSpeed + " " + strUnits);
}
private boolean useMetricUnits() {
// TODO Auto-generated method stub
CheckBox chkUseMetricUnits = (CheckBox) this.findViewById(R.id.chkMetricUnits);
return chkUseMetricUnits.isChecked();
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
if(location != null)
{
CLocation myLocation = new CLocation(location, this.useMetricUnits());
this.updateSpeed(myLocation);
}
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onGpsStatusChanged(int event) {
// TODO Auto-generated method stub
}
}
If you want to convert Meters/Second to kmph-1 then you need to multipl the Meters/Second answer from 3.6
Speed from kmph-1 = 3.6 * (Speed from ms-1)
GPS works fine in a vehicle. The NETWORK_PROVIDER setting might not be accurate enough to get a reliable speed, and the locations from the NETWORK_PROVIDER may not even contain a speed. You can check that with location.hasSpeed() (location.getSpeed() will always return 0).
If you find that location.getSpeed() isn't accurate enough, or it is unstable (i.e. fluctuates drastically) then you can calculate speed yourself by taking the average distance between a few GPS locations and divide by the time elapsed.
public class MainActivity extends Activity implements LocationListener {
add implements LocationListener next to Activity
LocationManager lm =(LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.onLocationChanged(null);
LocationManager.GPS_PROVIDER, 0, 0, The first zero stands for minTime and the second one for minDistance in which you update your values. Zero means basically instant updates which can be bad for battery life, so you may want to adjust it.
#Override
public void onLocationChanged(Location location) {
if (location==null){
// if you can't get speed because reasons :)
yourTextView.setText("00 km/h");
}
else{
//int speed=(int) ((location.getSpeed()) is the standard which returns meters per second. In this example i converted it to kilometers per hour
int speed=(int) ((location.getSpeed()*3600)/1000);
yourTextView.setText(speed+" km/h");
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
}
Don't forget the Permissions
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
We can use location.getSpeed();
try {
// Get the location manager
double lat;
double lon;
double speed = 0;
LocationManager locationManager = (LocationManager)
getActivity().getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
String bestProvider = locationManager.getBestProvider(criteria, false);
if (ActivityCompat.checkSelfPermission(getActivity(), 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);
try {
lat = location.getLatitude();
lon = location.getLongitude();
speed =location.getSpeed();
} catch (NullPointerException e) {
lat = -1.0;
lon = -1.0;
}
mTxt_lat.setText("" + lat);
mTxt_speed.setText("" + speed);
}catch (Exception ex){
ex.printStackTrace();
}
hello i'm pretty new to android..
i'm making an application which needs exact(approx 50m accuracy acceptable) user location..
i'm using locationmanager and locationlistener..
whenever i start the application i need user location returned. problem is that onlocationchanged method in locationlistener returns the latitude longitude only when they change..
how do i get user location ?
locmgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, loclist_netwk);
this is how i'm calling the class where i've implemented locationlistener.
`
package com.example.gpsmanager;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class MyLocationListener extends Activity implements LocationListener
{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylocation_layout);
}
#Override
public void onLocationChanged(Location loc) {
// TODO Auto-generated method stub
loc.getLatitude();
loc.getLongitude();
String text="my current location is"+"lat: "+loc.getLatitude()+"long: "+loc.getLongitude();
//TextView text1=(TextView) findViewById(R.id.textView1);
//text1.setText(text+"");
Toast.makeText(MyLocationListener.this, text, Toast.LENGTH_LONG).show();
}
#Override
public void onProviderDisabled(String arg0) {
// TODO Auto-generated method stub
String text="GPS Provider not availabe";
}
#Override
public void onProviderEnabled(String arg0) {
// TODO Auto-generated method stub
String text="GPS Provider availabe";
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
}
`
pllzz plzz help guys... thankss..
For user location you can use Reverse Geocoding
For it u have to send only lat,long.
Code is below:-
public String getAddress(double lat, double lng,Context mContext) {
Geocoder geocoder = new Geocoder(mContext, Locale.getDefault());
try {
List<Address> addresses = geocoder.getFromLocation(lat, lng,1);
String add="";
for(int i=0;i<addresses.size();i++){
Address obj = addresses.get(i);
//String = obj.getAddressLine(i);
add = add+obj.getAddressLine(i)+","+obj.getLocality()+","+obj.getAdminArea()+","+obj.getCountryName();
Log.v("IGA", "\n"+"Address " + add);
}
return add;
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show();
return null;
}
}
Greg
Here is my New code based on your suggestions. It did not work. I got a bunch of "Just sent a text message with coords" in a row. So it still is not sleeping for 15 seconds.
package com.droid.service;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
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.Handler;
import android.os.IBinder;
import android.os.Looper;
public class DroidService extends Service
{
private LocationManager lm;
private LocationListener locationListener;
private Location location = null;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
// #Override
// public void onCreate()
// {
// super.onCreate();
// initService();
// }
private static final int PERIOD = 15000;
Handler mHandler;
Runnable mRunnable;
#Override
public void onCreate()
{
super.onCreate();
mHandler = new Handler();
mRunnable = new Runnable()
{
public void run()
{
updateNotification();
mHandler.postDelayed(this, PERIOD);
System.out.println("PAUSE FOR 15 SECONDS..!!");
}
};
}
#Override
public void onStart(final Intent intent, final int startId)
{
super.onStart(intent, startId);
mRunnable.run();
}
// private void initService()
// {
// System.out.println("In initService..Droid Service...!!");
// int initialDelay = 15000; // start after 15 seconds
// // int period = 300000; // repeat every 5 minuets
// // int period = 1800000; // repeat every 30 minuets
// int period = 15000; // repeat every 15 seconds for testing
// Timer timer = new Timer();
// TimerTask task = new TimerTask()
// {
// public void run()
// {
// Looper.prepare();
// updateNotification();
// Looper.loop();
// }
// };
// timer.scheduleAtFixedRate(task, initialDelay, period);
// }
protected void updateNotification()
{
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new MyLocationlistener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
public static class DateUtils
{
public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
public static String now()
{
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
return sdf.format(cal.getTime());
}
}
private class MyLocationlistener implements LocationListener
{
public void onLocationChanged(Location loc)
{
double lat = loc.getLatitude();
double lon = loc.getLongitude();
String latitude = Double.toString(lat);
String longitude = Double.toString(lon);
String coords = latitude + longitude;
// comment out text message for debug mode
// SmsManager sm = SmsManager.getDefault();
// sm.sendTextMessage("phoneNumber", null, coords, null, null);
System.out.println("Just sent a text message with coords");
}
public void onProviderDisabled(String provider)
{
}
public void onProviderEnabled(String provider)
{
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
}
Here is my code
I get "Just sent a text message with coords" sent like once a second even though my scheduleAtFixedRate is set for 10 seconds.
I got this to work in a normal program, but on the Android platform, they want you to use Looper....and it appears that my code is caught up in this Looper so therefore it is ignoring my scheduleAtFixedRate(10 seconds)
Any help is greatly appreciated.
package com.droid.service;
import java.util.Timer;
import java.util.TimerTask;
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;
import android.os.Looper;
public class DroidService extends Service
{
private LocationManager lm;
private LocationListener locationListener;
private Location location = null;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public void onCreate()
{
super.onCreate();
initService();
}
private void initService()
{
System.out.println("In initService..!!");
int initialDelay = 15000; // start after 15 seconds
// int period = 300000; // repeat every 5 minuets
// int period = 1800000; // repeat every 30 minuets
int period = 15000; // repeat every 15 seconds for testing
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
public void run()
{
Looper.prepare();
updateNotification();
Looper.loop();
Looper.myLooper().quit();
}
};
timer.scheduleAtFixedRate(task, initialDelay, period);
}
protected void updateNotification()
{
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new MyLocationlistener();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
private class MyLocationlistener implements LocationListener
{
public void onLocationChanged(Location loc)
{
double lat = loc.getLatitude();
double lon = loc.getLongitude();
String latitude = Double.toString(lat);
String longitude = Double.toString(lon);
String coords = latitude + longitude;
// comment out text message for debug mode
// SmsManager sm = SmsManager.getDefault();
// sm.sendTextMessage("phoneNumber", null, coords, null, null);
System.out.println("Just sent a text message with coords");
}
public void onProviderDisabled(String provider)
{
}
public void onProviderEnabled(String provider)
{
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
}
I think the misconception here is not so much that Android wants to use a Looper, but thaty you shouldn't use the Timer for the behavior that you desire. Instead of the Timer you have to manipulate a Looper. I haven't used the Looper directly in a while because there are other components which abstract away a lot of the nuances of it. However I think that Looper.loop() should not return until an outside entity either interrupts your thread or quit's the looper for you. So I don't think that will work, I could be wrong though.
You could use a Handler if you want to create a pulse. A Handler allow you to do work on the Looper thread.
So with the example you have,
private static final int PERIOD = 15000;
Handler mHandler;
Runnable mRunnable;
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
mRunnable = new Runnable() {
public void run() {
updateNotication();
mHandler.postDelayed(this, PERIOD);
}
};
}
I will admit from here on out I am only guessing I know the desired outcome of your application. I am assuming you don't need two way communication as your IBinder is null.
#Override
public void onStart() {
mRunnable.run();
}
// The rest of your code.
..
Try to call initService from onStart().
Basically the best bet for me was to call this onCreate. Now it is doing exactly what I want it to do. Thanks for all your inputs..!! This helped me solve the problem.