I'm really sorry ahead of time, but this question is pretty lengthy.
I have a functioning GPSTracker class that contains the means of pinging GPS Location for a device. In my MainActivity, I have a button that uses the GPS tracker to display the location in a toast. I'm trying to convert this button into an automatic action to be repeated every X minutes, let's go with 10.(Right now the alarm receiver is setup for 10 seconds)
Even when the app is in the background. So I set up an AlarmReceiver to try to do this, but I can't quite get it working.
Here's my GPSTracker class:
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
public class GPSTracker extends Service implements LocationListener {
private final Context context;
boolean isGPSEnabled = false;
boolean canGetLocation = false;
boolean isNetworkEnabled = false;
Location location;
double latitude;
double longitude;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;
protected LocationManager locationManager;
public GPSTracker(Context context) {
this.context = context.getApplicationContext();
getLocation();
}
public Location getLocation(){
try {
locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if(!isGPSEnabled && !isNetworkEnabled) {
}else {
this.canGetLocation = true;
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if(locationManager != null){
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location !=null){
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
if(isGPSEnabled){
if(location == null){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
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;
}
public void stopUsingGPS() {
if(locationManager != null){
locationManager.removeUpdates(GPSTracker.this);
}
}
public double getLatitude() {
if(location!= null){
latitude = location.getLatitude();
}
return latitude;
}
public double getLongitude() {
if(location !=null){
longitude = location.getLongitude();
}
return longitude;
}
public boolean canGetLocation(){
return this.canGetLocation;
}
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setTitle("GPS is settings");
alertDialog.setMessage("GPS isn't enabled. Do you want to go to settings menu?");
alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
context.startActivity(intent);
}
});
alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int i) {
dialog.cancel();
}
});
alertDialog.show();
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
And here's my MainActivity:
package com.example.gwyn.locationnabtest;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends ActionBarActivity {
Button btnShowLocation;
Button btnStartService;
Button btnStopService;
GPSTracker gps;
//GoogleMap mMap;
private PendingIntent pendingIntent;
private AlarmManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnShowLocation = (Button) findViewById(R.id.show_location);
btnShowLocation.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
FragmentActivity activity = (FragmentActivity)view.getContext();
FragmentManager manager = activity.getSupportFragmentManager();
//MapFragment myMap = (MapFragment) (MainActivity.getFragmentManager()).findFragmentById((R.id.mapFragment));
// Test, remove me.
// mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapFragment)).getMap();
gps = new GPSTracker(MainActivity.this);
if(gps.canGetLocation()) {
// Location Achieved.
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();
// Draw Marker for Current Location on Fragment
// Currently Crashing App
// mMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title("Marker"));
// Toast a popup of the location data.
Toast.makeText(getApplicationContext(), "Your Location is -\nLat:" + latitude + "\nLong:" + longitude, Toast.LENGTH_LONG).show();
} else {
gps.showSettingsAlert();
}
}
});
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
btnStartService = (Button) findViewById(R.id.start_service);
btnStartService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval = 10000;
// 10 Second Interval. Good for testing, but turn this off.
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(getApplicationContext(), "Service Started", Toast.LENGTH_SHORT).show();
//startService(new Intent(getBaseContext(), MyServices.class));
}
});
btnStopService = (Button) findViewById(R.id.stop_service);
btnStopService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Cancel pending intents
manager.cancel(pendingIntent);
Toast.makeText(getApplicationContext(), "Pending Intents Cancelled", Toast.LENGTH_SHORT).show();
}
});
}
}
To highlight specifically, this is the part in MainActivity that works to display the GPS:
public void onClick(View view) {
FragmentActivity activity = (FragmentActivity)view.getContext();
FragmentManager manager = activity.getSupportFragmentManager();
//MapFragment myMap = (MapFragment) (MainActivity.getFragmentManager()).findFragmentById((R.id.mapFragment));
// Test, remove me.
// mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapFragment)).getMap();
gps = new GPSTracker(MainActivity.this);
if(gps.canGetLocation()) {
// Location Achieved.
double latitude = gps.getLatitude();
double longitude = gps.getLongitude();
// Draw Marker for Current Location on Fragment
// Currently Crashing App
// mMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title("Marker"));
// Toast a popup of the location data.
Toast.makeText(getApplicationContext(), "Your Location is -\nLat:" + latitude + "\nLong:" + longitude, Toast.LENGTH_LONG).show();
} else {
gps.showSettingsAlert();
}
}
My AlarmReceiver is as follows, and produces an error when creating the GPSTracker:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class AlarmReceiver extends BroadcastReceiver {
GPSTracker gps;
#Override
public void onReceive(Context arg0, Intent arg1) {
// Here's where we'd grab location and store it into DB.
//gps = new GPSTracker(AlarmReceiver.this);
// if(gps.canGetLocation()) {
// double latitude = gps.getLatitude();
// double longitude = gps.getLongitude();
// Draw Marker for Current Location on Fragment
// Toast a popup of the location data.
// Toast.makeText(arg0, "Your Location is -\nLat:" + latitude + "\nLong:" + longitude, Toast.LENGTH_LONG).show();
// } else {
// gps.showSettingsAlert();
// }
// Toast that the alarm ran.
Toast.makeText(arg0, "Location Pinged.", Toast.LENGTH_SHORT).show();
}
More specifically, a part of the problem is the way I'm calling for the new gps Tracker object here:
//gps = new GPSTracker(AlarmReceiver.this);
I'm not sure how to achieve the original result while using the alarmreceiver instead of a button, which is the main source of my problem. Does anyone know exactly what I can tinker with here to get the alarm receiver to properly use the GPSTracker Class?
DO not use GPSTracker. Its broken in over a dozen ways. Forget it exists. If you want a better version, you can use http://gabesechansoftware.com/location-tracking/ That link also explains why GPSTracker is broken by design and why it should never be used. It basically kinda works if used in optimal circumstances, and gives you horrible data in all the others.
Secondly, if you're using GPS and not network- you need to give it time to get a location sync. This can take seconds to minutes (or hours, if the user is in a basement or something) so the immediate forms of getting a location won't work- you have to wait for it to actually sync the location.
I suggest you not look for libraries to solve this and actually try to understand how the base APIs work. Until you do, you're going to have troubles with anything you use as there's lots of corner cases here and its not a trivial thing to do.
Related
I'm new to android app dev and Java isn't my strongest programming language.
I able to make my user to allow their location to be access or deny to get their location longitude and latitude number. Though, I still can't figure our how to implement the precision changes of the location to either increase or decrease their coordinate number. I read all the documentation for android in this topic and still don't understand it.
Here's the code:
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.google.android.material.snackbar.Snackbar;
public class Locator extends AppCompatActivity {
Button back;
private final String enable = "Enable yout location for the GPS to work";
private final String loading = "GPS is starting";
private final String latAndLong = "Latitude: %s\n Longitude: %s\n";
private LocationManager lm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.location);
back = findViewById(R.id.backbutton);
back.setOnClickListener(view -> {
Intent intent = new Intent(Locator.this, MainActivity.class);
startActivity(intent);
});
}
public void getLocation(View v) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, getResources().getInteger(R.integer.requestCode));
lm = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean isProviderEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!isProviderEnabled) {
Snackbar.make(v, enable, Snackbar.LENGTH_LONG).setAction("Action",
null).show();
} else {
userLoca();
}
}
private void userLoca() {
TextView tvLocation = findViewById(R.id.textView_locator);
if (ActivityCompat.checkSelfPermission(Locator.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
tvLocation.setText(getResources().getString(R.string.location_denied));
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, getResources().getInteger(R.integer.requestCode));
} else if (ActivityCompat.checkSelfPermission(Locator.this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
tvLocation.setText(getResources().getString(R.string.location_denied));
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, getResources().getInteger(R.integer.requestCode));
} else {
tvLocation = findViewById(R.id.textView_locator);
Location current_GPS = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Location networkLocation = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Location passiveLocation = lm.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
if (current_GPS != null) {
tvLocation.setText(String.format(latAndLong, current_GPS.getLatitude(),
current_GPS.getLongitude()));
}
if (networkLocation != null) {
tvLocation.setText(String.format(latAndLong, networkLocation.getLatitude(),
networkLocation.getLongitude()));
}
if (passiveLocation != null) {
tvLocation.setText(String.format(latAndLong, passiveLocation.getLatitude(),
passiveLocation.getLongitude()));
} else {
Snackbar.make(tvLocation, loading, Snackbar.LENGTH_LONG).setAction("Action",
null).show();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,
getResources().getInteger(R.integer.location_min_time),
getResources().getInteger(R.integer.location_min_dist), v -> {
});
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
getResources().getInteger(R.integer.location_min_time),
getResources().getInteger(R.integer.location_min_dist), v -> {
});
}
}
}
}
You need to implement location updates listener to this. Use the following code:
private LocationCallback locationCallback;
Call this in onCreate() or onResume() depending upon your logic
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
// Update UI with location data
// ...
}
}
};
private void startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
}
I used async task for upload image in the background thread to show a progress dialog. But while getting a location from async task, it throws the following error:
java.lang.RuntimeException: Can't create handler inside thread that
has not called Looper.prepare()
Although it is work without an async task. I want that process of getting location done in a background thread so that main thread can work without disturbance.
I got error in GPSlocater.java at locationmanager.requestLocationUpdates() while calling from async task.
So what should I do?
This is onLocate function which calls from mainActivity.java
public void onLocate(View view) {
asyncG asyncG1 = new asyncG(this);
asyncG1.execute();
}
This is a sub class which created in mainActivity.java
class asyncG extends AsyncTask
{
Context context;
ProgressDialog progressDialog;
public asyncG(MainActivity mainActivity) {
this.context = mainActivity;
}
#Override
protected Object doInBackground(Object[] objects) {
GPSlocater gpSlocater = new GPSlocater(context);
gpSlocater.getLocation();
lat = gpSlocater.getLatitude();
longi = gpSlocater.getLongitude();
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Finding Location");
progressDialog.show();
}
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
progressDialog.dismiss();
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
try {
List<Address> arr;
arr = geocoder.getFromLocation(lat,longi,1);
String pincode = arr.get(0).getPostalCode();
String stat = arr.get(0).getAdminArea();
String city1 = arr.get(0).getLocality();
String city2 = arr.get(0).getSubAdminArea();
String area1 = arr.get(0).getSubLocality();
String area2 = arr.get(0).getLocality();
if(pincode!=null && stat!=null)
{
state.setText(stat);
pin.setText(pincode);
}
if(city1!=null)
{
city.setText(city1);
}
else if(city2!=null)
{
city.setText(city2);
}
if(area1!=null)
{
area.setText(area1);
}
else if(area2!=null)
{
area.setText(area2);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
This is GPSlocater class which called from doInBackground
package com.example.samarth.serviceprovider1;
import android.app.AlertDialog;
import android.app.ProgressDialog;
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.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
public class GPSlocater 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 GPSlocater(Context context) {
this.mContext = context;
}
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
showSettingsAlert();
} 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(GPSlocater.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;
}
}
you need to create a handler to access UI elements from a thread.
https://developer.android.com/training/multiple-threads/communicate-ui.html
This tutorial should get you going, good luck (:
I'm trying to acquire GPS coordinates on my android application.
Criteria criteria = new Criteria();
criteria.setAltitudeRequired(false);
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setBearingRequired(false);
criteria.setCostAllowed(false);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
LocationManager locationManager =
(LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Intent i = new Intent(context, IntentListener.class);
i.setAction(Actions.ACTION_UPDATE_LOCATION);
PendingIntent pi = PendingIntent.getBroadcast(
context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
String provider = locationManager.getBestProvider(criteria, true);
if (provider == null) return;
locationManager.requestLocationUpdates(provider, 90 * 1000, 30, pi);
and here's receiving code.
Intent service = new Intent(context, WorkerService.class);
service.setAction(Actions.ACTION_UPDATE_LOCATION);
Location location = (Location) intent.getExtras().get(
LocationManager.KEY_LOCATION_CHANGED);
if (location == null) { // <-- Always true
return;
}
service.putExtra("lat", location.getLatitude());
service.putExtra("lon", location.getLongitude());
context.startService(service);
As you can see, I'm unable to obtain Location instance by calling intent.getExtras()... etc. Returned value is always null. I'm testing on my emulator running android 4.1.2 and telnet client, using geo fix longitude latitude. Anyone knows what's wrong? Thanks.
P.S. Manifest contains all required permissions and GPS is enabled in the emulator.
P.P.S. This application is a corporate app, that runs as a service, without UI and should collect GPS coordinates.
You casually mentioned that you're testing on an emulator. The emulator doesn't receive mock locations by itself; you have to specifically send them through the DDMS interface.
Additionally, due to a bug in the emulator, the time offset in incoming locations is set to midnight, so your location criteria will likely not match it.
I strongly suggest you test with a physical device to confirm that the problem is still occurring.
Use the new Location API.
You'd have to include Google Play services into your project.
Add this in onCreate:
mIntentService = new Intent(this,LocationService.class);
mPendingIntent = PendingIntent.getService(this, 1, mIntentService, 0);
int resp =GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(resp == ConnectionResult.SUCCESS){
locationclient = new LocationClient(this,this,this);
locationclient.connect();
}
And you'd have to override these methods:
#Override
protected void onDestroy() {
super.onDestroy();
if(locationclient!=null)
locationclient.disconnect();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "onConnected");
//to get last location
Location loc =locationclient.getLastLocation();
//to get updates via service
locationrequest = LocationRequest.create();
locationrequest.setInterval(100);
locationclient.requestLocationUpdates(locationrequest, mPendingIntent);
}
#Override
public void onDisconnected() {
Log.i(TAG, "onDisconnected");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
if(location!=null){
Log.i(TAG, "Location Request :" + location.getLatitude() + "," + location.getLongitude());
}
}
Here's the service where I'm creating a notification for every new location, you can remove that and update location there.
public class LocationService extends IntentService {
private String TAG = this.getClass().getSimpleName();
public LocationService() {
super("Fused Location");
}
public LocationService(String name) {
super("Fused Location");
}
#Override
protected void onHandleIntent(Intent intent) {
Location location = intent.getParcelableExtra(LocationClient.KEY_LOCATION_CHANGED);
if(location !=null){
Log.i(TAG, "onHandleIntent " + location.getLatitude() + "," + location.getLongitude());
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Builder noti = new NotificationCompat.Builder(this);
noti.setContentTitle("Fused Location");
noti.setContentText(location.getLatitude() + "," + location.getLongitude());
noti.setSmallIcon(R.drawable.ic_launcher);
notificationManager.notify(1234, noti.build());
}
}
}
Follow the tutorial to get the location in Android app
You should take your location by implementing LocationListener
#Override
public void onLocationChanged(Location loc) {
}
Take a look at this implementation, works really nice and i have tested it on several devices.
package ro.gebs.captoom.activities;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.bugsense.trace.BugSenseHandler;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import ro.gebs.captoom.R;
import ro.gebs.captoom.database.ReceiptDataSource;
import ro.gebs.captoom.utils.Constants;
import ro.gebs.captoom.utils.Utils;
public class LocationActivity extends FragmentActivity {
private GoogleMap map;
private long rec_id;
private String address;
private Marker selectedLoc;
private boolean isSessionClosed;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
BugSenseHandler.initAndStartSession(this, Constants.BugSenseKEY);
setContentView(R.layout.preview_location);
RelativeLayout cancel_btn = (RelativeLayout) findViewById(R.id.cancel_btn);
LinearLayout save_location_btn = (LinearLayout) findViewById(R.id.delete_btn);
save_location_btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (address != null) {
ReceiptDataSource r = new ReceiptDataSource();
r.updateReceiptLocation(rec_id, address);
Intent returnIntent = new Intent(getBaseContext(), EditReceiptActivity.class);
returnIntent.putExtra("result", address);
setResult(RESULT_OK, returnIntent);
finish();
} else {
Utils.showToast(getApplicationContext(), getString(R.string.c_unknownLocation), Toast.LENGTH_SHORT);
}
}
});
cancel_btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
if (map == null) {
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
if (isGoogleMapsInstalled()) {
if (map != null) {
retrieveLocation();
}
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Install Google Maps");
builder.setCancelable(false);
builder.setPositiveButton("Install", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.maps"));
startActivity(intent);
finish();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
}
#Override
protected void onResume() {
super.onResume();
if (isSessionClosed) {
BugSenseHandler.startSession(this);
isSessionClosed = false;
}
}
#Override
protected void onPause() {
super.onPause();
BugSenseHandler.closeSession(this);
isSessionClosed = true;
}
#Override
public void onBackPressed() {
map.clear();
super.onBackPressed();
}
private void retrieveLocation() {
Intent intent = getIntent();
address = intent.getStringExtra("location");
assert address != null;
if (address.equalsIgnoreCase("")) {
address = Utils.getCurrentLocation(LocationActivity.this);
}
rec_id = intent.getLongExtra("receipt_to_update_location", 0);
final Geocoder geocoder = new Geocoder(this, Locale.US);
double latitude = 0, longitude = 0;
try {
List<Address> loc = geocoder.getFromLocationName(address, 5);
if (loc.size() > 0) {
latitude = loc.get(0).getLatitude();
longitude = loc.get(0).getLongitude();
} else {
Utils.showToast(LocationActivity.this, getString(R.string.UnableToFindLocation), Toast.LENGTH_SHORT);
}
selectedLoc = map.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title(address).draggable(true));
map.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
#Override
public void onMarkerDragStart(Marker marker) {
}
#Override
public void onMarkerDrag(Marker marker) {
}
#Override
public void onMarkerDragEnd(Marker marker) {
try {
List<Address> addresses = geocoder.getFromLocation(selectedLoc.getPosition().latitude, selectedLoc.getPosition().longitude, 1);
StringBuilder sb = new StringBuilder();
if (addresses.size() > 0) {
Address address = addresses.get(0);
if (address.getAddressLine(0) != null)
sb.append(address.getAddressLine(0)).append(", ");
if (address.getLocality() != null)
sb.append(address.getLocality()).append(", ");
if (address.getCountryName() != null)
sb.append(address.getCountryName());
}
address = sb.toString();
} catch (IOException e) {
}
}
});
map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude, longitude), 12));
// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(12), 2000, null);
} catch (IOException e) {
Log.e("IOException", e.getMessage());
Utils.showToast(LocationActivity.this, getString(R.string.c_unknownLocation), Toast.LENGTH_LONG);
}
}
public boolean isGoogleMapsInstalled() {
try {
getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
}
I see you implement the intent.putExtra after you get the extra! You should do the put in the activity that receives the location data and when you want to receive the data from the intent.extra you should do this:
Bundle extras = getIntent().getExtras();
if (extras != null) {
latitude= (double)extras.getDouble("lat");
longitude=(double)extras.getDouble("lon");
}
I am new to android. i am trying to develop an app which fetch users current GPS coordinates and send them via sms to a hardcoded number. I am using two activities, first one has a progress bar and some text( Processing, Please wait),it is actually fetching GPS coordinates in background. The second one is receiving coordinates from first activity and sending the sms. The problem which i m facing is that in MainActivity.java file the condition if(latitude>0) is never satisfied since gps normally take some time to get coordinates and I cant go to second activity. I m attaching the code, please help me on this. you can edit the code if u like.
Thanks in Advance.
package com.shaji.smartcab;
import com.shaji.smartcab.MainActivity;
import com.shaji.smartcab.MyLocationListener;
import com.shaji.smartcab.R;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;
import android.location.LocationListener;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
public class MainActivity extends Activiy{
double lat;
double lon;
String coordinates;
String coor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv= (TextView) findViewById(R.id.textView1);
LocationManager mlocManager=null;
LocationListener mlocListener;
mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 600,10, mlocListener);
if (mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
if(MyLocationListener.latitude>0) {
lat = MyLocationListener.latitude;
lon = MyLocationListener.longitude;
tv.setText("m fetching coordinates");
coordinates= lat+","+lon;
Intent intent = new Intent(MainActivity.this, Sec.class);
intent.putExtra(coor, coordinates);
startActivity(intent);
//tv1.setText("Latitude:" + MyLocationListener.latitude + ",Longitude:" + MyLocationListener.longitude );
}}
else {
Context context = getApplicationContext();
CharSequence text = "Please turn ON GPS and Try again Later!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
tv.setText(" ");
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}}
enter code herepackage com.shaji.smartcab;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
public class MyLocationListener implements LocationListener {
public static double latitude;
public static double longitude;
#Override
public void onLocationChanged(Location loc)
{
loc.getLatitude();
loc.getLongitude();
latitude=loc.getLatitude();
longitude=loc.getLongitude();
}
#Override
public void onProviderDisabled(String provider)
{
//print "Currently GPS is Disabled";
}
#Override
public void onProviderEnabled(String provider)
{
//print "GPS got Enabled";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
}
//this is the second activity.
package com.shaji.smartcab;
import com.shaji.smartcab.R;
import android.app.Activity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class Sec extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
final String sms = (String) getIntent().getExtras().get("coor");
Button c = (Button) findViewById(R.id.button1);
c.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
String phoneNo = "03136166588";
//String sms = "coordinates";
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, sms, null, null);
Toast.makeText(getApplicationContext(), "Request Sent!",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(),
" Error, please try again later!",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}});
}}
I think the problem is, location update is not done before you call the next Activity.
Before you get the updates, get the co-ordinates using one of the 3 providers. Refer following code.
private Location getUserLocation() {
location_manager = (LocationManager) getSystemService(LOCATION_SERVICE);
if (location_manager != null) {
List<String > provider=location_manager .getAllProviders();
Location location = null;
for(int i=0;i<provider.size();i++){
location=location_manager .getLastKnownLocation(provider.get(i));
if(location!=null){
location_manager.requestLocationUpdates(provider.get(i),
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES,mlocListener);
break;
}
}
return location;
}
}
I want to reload MainActivity after data change. So I wrote this code and it working well.
This is from MainActivity, that i want to reload:
public class MainActivity extends Activity {
private static final int RESULT_SETTINGS = 1;
LinearLayout horizontalForecast, todayForecast, tomorrowForecast;
TextView ViewSunRise, ViewSunSet, NowTatva, NextTejas, Longitude, Latitude, BeziT, TatvicForecast;
TextView Today, Tomorrow, NextTatva;
GPSTracker gps;
ImageView img;
TabHost th;
public void reload() {
finish();
Intent i2 = new Intent(MainActivity.this, MainActivity.class);
startActivityForResult(i2, RESULT_SETTINGS);
}
}
But when I call this from another Class (not an activity), it doesn't work.
This is from another Class:
package com.reversity.simpletatva;
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;
MainActivity MA;
boolean ch = false;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
Location location = null; // location
double latitude = Double.NaN; // latitude
double longitude = Double.NaN; // 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
protected static final int RESULT_SETTINGS = 1;
// 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");
// Setting Dialog Message
alertDialog.setMessage("GPS není zapnuta, lokace byla nastavena na 0. Chcete přejít do nastavení nebo nastavit vlastní?");
// On pressing Settings button
alertDialog.setPositiveButton("Nastavení", 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("Použít vlastní", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent(mContext, Preference.class);
mContext.startActivity(i);
}
});
// Showing Alert Message
alertDialog.show();
}
#Override
public void onLocationChanged(Location location) {
/*
Toast changed = Toast.makeText(mContext, "Location changes", Toast.LENGTH_LONG);
changed.show();
MA.reload();
startActivity(new Intent(mContext, MainActivity.class));
invalidate();
*/
stopUsingGPS();
MainActivity mainActivity = new MainActivity ();
mainActivity.reload();
}
#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;
}
public Boolean locChanged(){
return ch;
}
}
So I want to Reload MainActivity from GPSTracker Class when onLocationChanged();
I don't find answer that will be usefull for me. So I ask this question. Don't blame me.
I just need how can I call the MainActivity to reload from GPSTracker Class.
I tried everything I know. But it isn't working and Aplication will close.
Error NullPointerException
You're trying to call a non-static method from a static context.
Either make your reload method static, or use a reference to an instance of MainActivity (e.g. MainActivity myActivity; myActivity.reload())
Alternatively, perhaps you meant for Activity2 to extend MainActivity?
You need to pass the second class a reference to MainActivity, and call reload() on that reference.
For a generic class:
public class SecondClass {
MainActivity mActivity;
// Constructor where you pass a reference to MainActivity
public SecondClass(Activity activity) {
mActivity = activity;
}
public onChange() {
mActivity.reload();
}
}
When you initialize the SecondClass in MainActivity you pass a reference to MainActivity
SecondClass secondClass = new SecondClass(this);
Then you can use onChange(), and MainActivity.reload() should get called.
secondClass.onChange();
EDIT:
Well, now that you updated your question, my answer is no longer correct. Since your second class is a Service, keeping references to your MainActivity might create memory leaks.
I would solve this with registering a BroadcastReceiver in your MainActivity. In your Service, you broadcast an Intent when an updated is needed.
This would look something like this:
In MainActivity:
public void MainActivity extends Activity {
private BroadcastReceiver mReceiver;
#Override
public void onCreate(Bundle savedInstanceState) {
.
.
.
// We listen for a broadcasted Intent with
// action = com.example.ACTION_RELOAD_MAINACTIVITY
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.ACTION_RELOAD_MAINACTIVITY");
// Init the receiver
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Reload when we receive the broadcast
MainActivity.this.reload();
}
}
// Register the receiver
registerReceiver(mReceiver, filter);
}
// In onDestroy() we unregister the receiver
#Override
public void onDestroy() {
unregisterReceiver(mReceiver);
}
}
In your Service, you now have to broadcast an Intent when you want to reload MainActivity.
public class GPSTracker extends Service implements LocationListener {
.
.
.
#Override
public void onLocationChanged(Location location) {
// Create an Intent with
// action = com.example.ACTION_RELOAD_MAINACTIVITY
Intent i = new Intent("com.example.ACTION_RELOAD_MAINACTIVITY");
// As a side note; You can use this Intent to send data to MainActivity.
// If you want to pass the Location object of onLocationChanged() to
// MainActivity, you would simply call i.putExtra("current_location", location)
// The data can then be fetched using the supplied Intent in onReceive().
// Broadcast that Intent
sendBroadcast(i);
}
}
what you can do just add this in the Androidmanifest.xml file where you declared your main activity inside the activity tag
android:finishOnTaskLaunch="true"
and remove finish(); from the reload method.
Now in GPSTracker class just start the activity by calling
Intent intent=new Intent(mContext,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);