Android drawing marker dynamically in bradcast receiver - java

I am sending latitude and longitude I received from my server and passing them to broadcastreceiver to draw a marker and update it's location continuously based on the updates it receives from the server. The location updates are coming from another device and I am tracking that device and display it's location in my app as follows:
#Override
public void onMessageReceived(String from, Bundle data) {
if (data != null && !data.isEmpty()) {
String lati = data.getString("lati");
String longi = data.getString("longi");
Intent mIntent = new Intent();
mIntent.putExtra(LOCATION, lati + "," + longi);
mIntent.setAction(UPDATE_COORDINATES); //should match the receiver intent filter at the registering
coordintesupdater.sendBroadcast(mIntent);
} else {
Log.i("Received", "empty message");
}
}
This is my broadcast receiver that is not being called nor does it receive the latitude and longitude.
private BroadcastReceiver locationupdatesreceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String messagestr = intent.getStringExtra(MyGcmListenerService.UPDATE_COORDINATES);
String latst = "", lonst = "";
double lati, longi;
if (messagestr != null && !messagestr.isEmpty()) {
String[] separated = messagestr.split(",");
latst = separated[0].trim();
lonst = separated[1].trim();
try {
lati = Double.parseDouble(separated[0].trim());
longi = Double.parseDouble(separated[1].trim());
//cLocation.setLatitude(lati);
//cLocation.setLongitude(longi);
LatLng updatedloc = new LatLng(lati, longi);
//draw the cab and update it's location periodically
drawLocationUpdatesonMap(updatedloc);
}catch (NumberFormatException nfe){
nfe.printStackTrace();
}
}
}
};
private void drawLocationUpdatesonMap(final LatLng newlocatioin){
GoogleMap.OnMyLocationChangeListener mLoChangeListnener = new OnMyLocationChangeListener() {
#Override
public void onMyLocationChange(Location location) {
//if (cMarker != null)
// cMarker.remove();
Log.i("device location", newlocatioin.toString());
cabMarker = map.addMarker(new MarkerOptions()
.position(newlocatioin)
.visible(true)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.mmovingc))
.flat(true));
}
};
map.setOnMyLocationChangeListener(mLoChangeListnener);
}
FYI the GcmListenerservice is a nested class of my map activity.

It's so embarrassing. I forgot to register and unregister the broadcastreceiver in OnResume and Onpause respectively. It now works like a charm.

Related

location does't update after calling update function

I am implementing an android application in java to retrieve Location but the location doesn't update every time i call the function , it always returns me the same positions and i don't understand why.First i collect the position by calling the getCurrentLocation function ,then the callbackLocation function to update the location and finally the onstartLocationUpdates() to call the callbackLocation function; .I also allow all the permission when launching the app. Here is the code i've implemented :
public class TimeService extends Service {
private final static String TAG = TimeService.class.getName();
BroadcastReceiver mReceiver;
private LocationCallback locationCallback;
LocationRequest locationRequest;
FusedLocationProviderClient fusedClient;
double Longitude, Latitude, Altitude;
float Accuracy;
#Override
public void onCreate() {
super.onCreate();
fusedClient = LocationServices.getFusedLocationProviderClient(this);
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter("sendLocationIntent"));
getCurrentLocation();
callbackLocation();
}
//Here when i am trying to update the location when i receive the upcoming message
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals("sendLocationIntent")) {
return;
}
onstartLocationUpdates();
String socket_id = intent.getStringExtra("socket_id");
String messageTosend = Latitude + ":" + Longitude + ":" + Altitude + ":" + Accuracy + ":" + socket_id + ":" + globals.getDeviceIMEI(TimeService.this);
;
sendLocationMessageWithStatus();
}
};
protected void sendLocationMessageWithStatus(String phoneNumber, String Msg) {
//Send message block
}
public void getCurrentLocation() {
fusedClient.getLastLocation()
.addOnSuccessListener(getMainExecutor(), new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location != null) {
Latitude = location.getLatitude();
Longitude = location.getLongitude();
Accuracy = location.getAccuracy();
}
}
});
//Setting
createLocationRequest();
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
task.addOnSuccessListener(getMainExecutor(), new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
}
});
}
protected void createLocationRequest() {
locationRequest = new LocationRequest();
LocationRequest.Builder locationRequestBuilder = new LocationRequest.Builder(locationRequest);
locationRequestBuilder.setIntervalMillis(10000);
locationRequestBuilder.setMinUpdateIntervalMillis(5000);
locationRequestBuilder.setPriority(Priority.PRIORITY_HIGH_ACCURACY);
}
private void onstartLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
fusedClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
private void callbackLocation(){
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
Latitude = location.getLatitude();
Longitude = location.getLongitude();
Accuracy = location.getAccuracy();
}
}
};
}
}

Android: Geofencing is working fine when its in foreground but not working in background

I am a novice in Android development. I tried to develop an Android app which will show a Google Map with a fixed Geofence Area and the current location of the concerned person. Whenever he / she leaves or enters that particular geofence region a notification will be shown. After searching various forums and stackoverflow for ideas I somehow manged to develop the application. But I am now facing the problem that it shows the notfication about the Entry / exit of Geofence area only when the app is open. If it is minimized and swiped out it doesn't run in background. I used GeofenceTransitionsJobIntentService for geofence transition changes. I think that I had done some silly mistake so it's not working in background. So please help me out from this problem.
Here's the full code. Any ideas where I'm going wrong ? Thanks in Advance
My codes:
GeofenceTransitionsJobIntentService.Java
public class GeofenceTransitionsJobIntentService extends JobIntentService {
private static final int JOB_ID = 573;
private static final String TAG = "GeofenceTransitionsIS";
private static final String CHANNEL_ID = "channel_01";
/**
* Convenience method for enqueuing work in to this service.
*/
public static void enqueueWork(Context context, Intent intent) {
enqueueWork(context, GeofenceTransitionsJobIntentService.class, JOB_ID, intent);
}
/**
* Handles incoming intents.
* #param intent sent by Location Services. This Intent is provided to Location
* Services (inside a PendingIntent) when addGeofences() is called.
*/
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onHandleWork(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceErrorMessages.getErrorString(this,
geofencingEvent.getErrorCode());
Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger multiple geofences.
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(geofenceTransition,
triggeringGeofences);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition));
}
}
/**
* Gets transition details and returns them as a formatted string.
*
* #param geofenceTransition The ID of the geofence transition.
* #param triggeringGeofences The geofence(s) triggered.
* #return The transition details formatted as String.
*/
private String getGeofenceTransitionDetails(
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
// Get the Ids of each geofence that was triggered.
ArrayList<String> triggeringGeofencesIdsList = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}
/**
* Posts a notification in the notification bar when a transition is detected.
* If the user clicks the notification, control goes to the MainActivity.
*/
private void sendNotification(String notificationDetails) {
// Get an instance of the Notification manager
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Android O requires a Notification Channel.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.app_name);
// Create the channel for the notification
NotificationChannel mChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH);
// Set the Notification Channel for the Notification Manager.
mNotificationManager.createNotificationChannel(mChannel);
}
// Create an explicit content Intent that starts the main Activity.
Intent notificationIntent = new Intent(getApplicationContext(), MapsActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(MapsActivity.class);
// Push the content Intent onto the stack.
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack.
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
// Define the notification settings.
builder.setSmallIcon(R.drawable.ic_launcher)
// In a real app, you may want to use a library like Volley
// to decode the Bitmap.
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher))
.setColor(Color.RED)
.setOngoing(false)
.setPriority(Notification.PRIORITY_DEFAULT)
.setContentTitle(notificationDetails)
.setTicker(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Set the Channel ID for Android O.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID); // Channel ID
}
// Dismiss notification once the user touches it.
builder.setAutoCancel(true);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
/**
* Maps geofence transition types to their human-readable equivalents.
*
* #param transitionType A transition type constant defined in Geofence
* #return A String indicating the type of transition
*/
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return getString(R.string.geofence_transition_entered);
case Geofence.GEOFENCE_TRANSITION_EXIT:
return getString(R.string.geofence_transition_exited);
default:
return getString(R.string.unknown_geofence_transition);
}
}
}
GeofenceBroadcastReceiver.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsJobIntentService.enqueueWork(context, intent);
}
}
MapsActivity.java
public class MapsActivity extends AppCompatActivity implements
GoogleMap.OnMyLocationButtonClickListener, OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, OnCompleteListener<Void>
{
private static final String TAG = MapsActivity.class.getSimpleName();
static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
static final int RADIUS = 500;
private LocationManager locationManager;
private String provider;
private Location location;
private GoogleMap mMap;
private Circle circle;
private PendingIntent geofencePendingIntent;
private GeofencingClient geofencingClient;
private GoogleApiClient googleApiClient;
private boolean isContinue = false;
private boolean isGPS = false;
private LocationRequest locationRequest;
private final int UPDATE_INTERVAL = 2 * 60 * 1000;
private final int FASTEST_INTERVAL = 20 * 1000;
private final int NOTIFICATION_RESPONSIVENESS_TIME = 10000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
geofencingClient = LocationServices.getGeofencingClient(this);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
createGoogleApi();
new GpsUtils(this).turnGPSOn(new GpsUtils.onGpsListener() {
#Override
public void gpsStatus(boolean isGPSEnable) {
// turn on GPS
isGPS = isGPSEnable;
}
});
if (!checkPermissions()) {
requestPermissions();
}
}
#Override
public void onMapReady(GoogleMap googleMap)
{
Log.d(TAG,"onMapReady()");
mMap = googleMap;
mMap.setOnMyLocationButtonClickListener(this);
addGeofence(getMyLocation(), RADIUS);
drawCircle(getMyLocation(), RADIUS);
markerForGeofence(getMyLocation());
}
private void createGoogleApi()
{
if(googleApiClient==null)
{
googleApiClient=new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
public void onStart() {
super.onStart();
googleApiClient.connect();
if (checkPermissions()) {
// removeGeofence();
addGeofence(getMyLocation(), RADIUS);
// drawCircle(getMyLocation(), RADIUS);
// markerForGeofence(getMyLocation());
} else {
requestPermissions();
}
}
#Override
public void onStop() {
super.onStop();
googleApiClient.disconnect();
}
#Override
public void onConnected(#Nullable Bundle bundle)
{
Log.i(TAG, "onConnected()");
getLastKnownLocation();
addGeofence(getMyLocation(), RADIUS);
drawCircle(getMyLocation(), RADIUS);
markerForGeofence(getMyLocation());
}
#Override
public void onConnectionSuspended(int i)
{
Log.w(TAG, "onConnectionSuspended()");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult)
{
Log.w(TAG, "onConnectionFailed()");
}
// Get last known location
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if ( checkPermissions() ) {
location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if ( location != null ) {
Log.i(TAG, "LasKnown location. " +
"Long: " + location.getLongitude() +
" | Lat: " + location.getLatitude());
writeLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
}
else requestPermissions();
}
// Start location Updates
private void startLocationUpdates(){
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if ( checkPermissions() )
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged ["+location+"]");
location = location;
writeActualLocation(location);
addGeofence(getMyLocation(), RADIUS);
}
// Write location coordinates on UI
private void writeActualLocation(Location location) {
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private void writeLocation() {
writeActualLocation(location);
}
private Marker locationMarker;
// Create a Location Marker
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation("+latLng+")");
String title = "Your Current Location("+latLng.latitude + ", " + latLng.longitude+")";
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if ( mMap!=null ) {
// Remove the anterior marker
if ( locationMarker != null )
locationMarker.remove();
locationMarker = mMap.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
mMap.animateCamera(cameraUpdate);
}
}
private Marker geoFenceMarker;
// Create a marker for the geofence creation
private void markerForGeofence(LatLng latLng) {
Log.i(TAG, "markerForGeofence("+latLng+")");
String title = "Your Geofence Area("+latLng.latitude + ", " + latLng.longitude+")";
// Define marker options
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
.title(title);
if ( mMap!=null ) {
// Remove last geoFenceMarker
if (geoFenceMarker != null)
geoFenceMarker.remove();
geoFenceMarker = mMap.addMarker(markerOptions);
}
}
/**
* Return the current state of the permissions needed.
*/
private boolean checkPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED )
{
return false;
}
else
{
return true;
}
}
private void requestPermissions() {
boolean shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION);
boolean shouldProvideRationale1 =
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION);
// Provide an additional rationale to the user. This would happen if the user denied the
// request previously, but didn't check the "Don't ask again" checkbox.
if (shouldProvideRationale || shouldProvideRationale1) {
Log.i(TAG, "Displaying permission rationale to provide additional context.");
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
#Override
public void onClick(View view) {
// Request permission
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
})
.show();
} else {
Log.i(TAG, "Requesting permission");
// Request permission. It's possible this can be auto answered if device policy
// sets the permission in a given state or the user denied the permission
// previously and checked "Never ask again".
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
}
// For creating GeoFence.
private Geofence createGeofence(LatLng latLng, int radiusMeters) {
return new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId("1")
.setCircularRegion(latLng.latitude, latLng.longitude, radiusMeters)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(NOTIFICATION_RESPONSIVENESS_TIME)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
private GeofencingRequest getGeofencingRequest(LatLng latLng, int radiusMeters) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofence(createGeofence(latLng, radiusMeters));
return builder.build();
}
/**
* Callback received when a permissions request has been completed.
*/
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == MY_PERMISSIONS_REQUEST_LOCATION) {
if (grantResults.length <= 0) {
// If user interaction was interrupted, the permission request is cancelled and you
// receive empty arrays.
Log.i(TAG, "User interaction was cancelled.");
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED && grantResults[2] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
getLastKnownLocation();
}
} else {
// Permission denied.
// setButtonsState(false);
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_denied_explanation,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.settings, new View.OnClickListener() {
#Override
public void onClick(View view) {
// Build intent that displays the App settings screen.
Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}).show();
}
}
}
#Override
public boolean onMyLocationButtonClick() {
// Return false so that we don't consume the event and the default behavior still occurs
// (the camera animates to the user's current position).
/* if (circle != null)
circle.remove();
drawCircle(getMyLocation(), RADIUS);*/
return false;
}
private void drawCircle(LatLng latLng, int radius) {
circle = mMap.addCircle(new CircleOptions()
.center(latLng)
.radius(radius)
.strokeWidth(0f)
.fillColor(0x55FF0000));
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (geofencePendingIntent != null) {
return geofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return geofencePendingIntent;
}
private void removeGeofence() {
geofencingClient.removeGeofences(getGeofencePendingIntent()).addOnCompleteListener(this);
}
private void addGeofence(LatLng latLng, int radiusMeters) {
geofencingClient.addGeofences(getGeofencingRequest(latLng, radiusMeters), getGeofencePendingIntent())
.addOnCompleteListener(this);
}
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
}
}
}
Run Foreground service, when App goes to background. This solves your problem.
On Android 8.0 (API level 26) and higher, if an app is running in the background while monitoring a geofence, then the device responds to geofencing events every couple of minutes. To learn how to adapt your app to these response limits, see Background Location Limits.
You might need to run a sticky foreground service for your app to be running continuously.

location returns null when started the first time

For my app, I need to get the location of the user, to fetch corresponding data from a server. The problem is that the code I use doesn't properly return the location when it's opened the first time. After restarting the app once it works just fine. I searched the other questions and found out, that if you use getLastKnownLocation and there is no location since the last reboot, it returns null. But why does it work when the app is restarted? Does it fetch it when it's opened the first time, and how can I make it wait until the location is fetched properly at the first opening then?
The code of my MainActivity:
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 123);
} else {
progressBar.setVisibility(View.VISIBLE);
GPSClass gt = new GPSClass(getActivity().getApplicationContext());
Location location = gt.getLocation();
if (location == null) {
//Toast
} else {
lat = location.getLatitude();
lon = location.getLongitude();
}
new GetContacts().execute();
}
And the GPSClass:
public class GPSClass implements LocationListener {
Context context;
public GPSClass(Context context) {
super();
this.context = context;
}
public Location getLocation(){
if (ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) {
Log.e("fist","error");
return null;
}
try {
LocationManager lm = (LocationManager) context.getSystemService(LOCATION_SERVICE);
boolean isGPSEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled){
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000,10,this);
Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
return loc;
}else{
Log.e("sec","error");
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
Here is the full tutorial
I shared a tutorial link follow that link.
Call this below method. It will return value; when lat and long is found. Until object is null or doesn't return any value your app must be idle or show some progress value or tell the user to wait.
InitGeoLocationUpdate.locationInit(SplashScreen.this,
object -> {
double latitude = object.latitude;
double longitude = object.longitude;
Lg.INSTANCE.d(TAG, "Current Location Latitude: " + latitude + " Longitude: " +
longitude);
});
Try this this will not give you null current location
class GetLastLocation extends TimerTask {
LocationManager mlocManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocListenerTmp = new CustomLocationListener();
private final Handler mLocHandler;
public GetLastLocation(Handler mLocHandler) {
this.mLocHandler = mLocHandler;
}
#Override
public void run() {
timer.cancel();
mlocManager.removeUpdates(mlocListenerTmp);
Location location = mlocManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
{
if (mlocListenerTmp != null) {
mlocManager.removeUpdates(mlocListenerTmp);
}
currentLocation = location;
}
if (location != null) {
String message = String.format(
"Location \n Longitude: %1$s \n Latitude: %2$s",
location.getLongitude(), location.getLatitude());
Log.d("loc", " :" + message);
Bundle b = new Bundle();
{
b.putBoolean("locationRetrieved", true);
{
Message msg = Message.obtain();
{
msg.setData(b);
mLocHandler.sendMessage(msg);
}
}
}
} else {
Log.d(
"loc",
":No GPS or network signal please fill the location manually!");
location = mlocManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
currentLocation = location;
Bundle b = new Bundle();
{
b.putBoolean("locationRetrieved", true);
{
Message msg = Message.obtain();
{
msg.setData(b);
mLocHandler.sendMessage(msg);
}
}
}
} else {
Bundle b = new Bundle();
{
b.putBoolean("locationRetrieved", false);
{
Message msg = Message.obtain();
{
msg.setData(b);
mLocHandler.sendMessage(msg);
}
}
}
}
}
}
}
call it like this in your MainActivity
timer.schedule(new GetLastLocation(mLocHandler), 3000);
and the customLocationclass is as follows:
public class CustomLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
loc.getLatitude();
loc.getLongitude();
currentLocation = loc;
String Text = "My current location is: " + "Latitud = "
+ loc.getLatitude() + "Longitud = " + loc.getLongitude();
Log.d("loc", "onLocationChanged" + Text);
}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}

How to plot on maps from arraylist with lon/lat?

This is my Map Class...
public class Mapa extends FragmentActivity implements LocationListener {
public GoogleMap map;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mapa);
Getting Google Play availability status
int status =GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
Showing status
if(status!=ConnectionResult.SUCCESS){ // Google Play Services are not available
int requestCode = 10;
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
dialog.show();
}else {
Getting reference to the SupportMapFragment
SupportMapFragment fm = (SupportMapFragment)
getSupportFragmentManager().findFragmentById(R.id.map);
Getting GoogleMap object from the fragment
map = fm.getMap();
Enabling MyLocation Layer of Google Map
map.setMyLocationEnabled(true);
Getting LocationManager object from System Service LOCATION_SERVICE
LocationManager locationManager = (LocationManager)
getSystemService(LOCATION_SERVICE);
Creating a criteria object to retrieve provider
Criteria criteria = new Criteria();
Getting the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
Getting Current Location
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
onLocationChanged(location);
}
locationManager.requestLocationUpdates(provider, 20000, 0, this);
}
}
public void onLocationChanged(Location location) {
TextView tvLocation = (TextView) findViewById(R.id.tv_location);
Getting latitude of the current location
double latitude = location.getLatitude();
Getting longitude of the current location
double longitude = location.getLongitude();
Creating a LatLng object for the current location
LatLng latLng = new LatLng(latitude, longitude);
Showing the current location in Google Map
map.moveCamera(CameraUpdateFactory.newLatLng(latLng));
Zoom in the Google Map
map.animateCamera(CameraUpdateFactory.zoomTo(15));
Setting latitude and longitude in the TextView tv_location
tvLocation.setText("Latitude:" + latitude + ", Longitude:"+ longitude );
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
And this is my class with the arraylist
public void getPontos(View view) {
String codigo;
codigo = linhaList.get(spinner.getSelectedItemPosition()).getCodigo();
new WebServiceGetPontosLinha().execute(codigo);
}
private class WebServiceGetPontosLinha extends
AsyncTask<String, Void, Void> {
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(MainActivity.this, "",
getResources().getText(R.string.connecting), true, false);
}
#Override
protected Void doInBackground(String... params) {
WebServiceConsumer webServiceConsumer = new WebServiceConsumer(
MainActivity.this);
pontoList = webServiceConsumer.getPontos(params[0]);
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
pontoArrayAdapter = new ArrayAdapter<PontosLinhas>(
MainActivity.this,
android.R.layout.simple_spinner_dropdown_item, pontoList);
spinner1.setAdapter(pontoArrayAdapter);
}
}
How do I plot the content of spinner on maps like an image?
This involves a lot of details which is not needed for your but hope you get the picture.
I developed an app that among other things shows the location of hydrants on a map and this is how I load the hydrants to the map:
private class LoadHydrantsToMapTask extends
AsyncTask<Hydrant, Integer, List<MarkerOptions>> {
private int loadHydrantsGoal = 0;
public LoadHydrantsToMapTask(int loadHydrantsGoal) {
this.loadHydrantsGoal = loadHydrantsGoal;
}
// Before running code in separate thread
#Override
protected void onPreExecute() {
Device.lockOrientation((Activity)context);
// Create a new progress dialog.
progressDialog = new ProgressDialog(context);
// Set the progress dialog to display a horizontal bar .
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage(context
.getString(R.string.adding_hydrants));
// This dialog can't be canceled by pressing the back key.
progressDialog.setCancelable(false);
// This dialog isn't indeterminate.
progressDialog.setIndeterminate(false);
// The maximum number of progress items is 100.
progressDialog.setMax(loadHydrantsGoal);
// Set the current progress to zero.
progressDialog.setProgress(0);
// Display the progress dialog.
progressDialog.show();
}
// The code to be executed in a background thread.
#Override
protected List<MarkerOptions> doInBackground(Hydrant... hydrants) {
List<MarkerOptions> markers = new ArrayList<MarkerOptions>();
for (Hydrant hydrant : hydrants) {
final String hydrant_type = hydrant.getHydrantType();
final String hydrant_icon_path = hydrant.getIconPath();
double latitude = hydrant.getLatitude();
double longitude = hydrant.getLongitude();
final LatLng position = new LatLng(latitude, longitude);
final String address = hydrant.getAddress();
final String addressNumber = hydrant.getAddressNumber();
final String addressremark = hydrant.getAddressRemark();
final String remark = hydrant.getRemark();
BitmapDescriptor icon = BitmapDescriptorFactory
.defaultMarker(BitmapDescriptorFactory.HUE_RED);
if (!hydrant_icon_path.isEmpty()) {
File iconfile = new File(hydrant_icon_path);
if (iconfile.exists()) {
BitmapDescriptor loaded_icon = BitmapDescriptorFactory
.fromPath(hydrant_icon_path);
if (loaded_icon != null) {
icon = loaded_icon;
} else {
Log.e(TAG, "loaded_icon was null");
}
} else {
Log.e(TAG, "iconfile did not exist: "
+ hydrant_icon_path);
}
} else {
Log.e(TAG, "iconpath was empty on hydrant type: "
+ hydrant_type);
}
StringBuffer snippet = new StringBuffer();
if (!address.isEmpty())
snippet.append("\n" + address + " " + addressNumber);
if (addressremark.isEmpty())
snippet.append("\n" + addressremark);
if (!remark.isEmpty())
snippet.append("\n" + remark);
markers.add(new MarkerOptions().position(position)
.title(hydrant_type).snippet(snippet.toString())
.icon(icon));
publishProgress(markers.size());
}
return markers;
}
// Update the progress
#Override
protected void onProgressUpdate(Integer... values) {
// set the current progress of the progress dialog
progressDialog.setProgress(values[0]);
}
// after executing the code in the thread
#Override
protected void onPostExecute(List<MarkerOptions> markers) {
GoogleMap map = GoogleMapsModule.getInstance().getMap();
for (MarkerOptions marker : markers) {
if (marker != null)
map.addMarker(marker);
}
if (markers.size() == mHydrants.size()) {
setAllHydrantAdded(true);
setNearbyHydrantsAdded(true);
} else {
setNearbyHydrantsAdded(true);
}
Device.releaseOrientation((Activity) context);
}
}
When I call the task, I have a list of Hydrant objects. To parse the list to the AsyncTask I convert the list into an Array:
new LoadHydrantsToMapTask(hydrants.size()).execute(hydrants
.toArray(new Hydrant[hydrants.size()]));

app crashes when intent passes variable to another activity

i am making a app that tracks the user and tracks another user which in theory would be an animal.
my app goes like this, you register a username and pass then when this is done the user can log into the map by reentering the correct username and password. This is where the issues begin.
upon creation of the screen the map loads with the users current location and auto sends a sms to the "animals" phone to request gps details, this then sends back 2 sms messages, 1 containing the gps information. i have a SmsReceiver class which reads this information and extracts the longitude and latitude data, converts it into a double then passes it to the map activity to be converted into a lnglat variable and displayed on the google map with a marker. Now the issue i am having is that it can take several minutes for the sms to return with the gps information, when this is done and the intent is used to send the coordinates to the map page a button must be clicked so that the longitude and latitude are combined into the AnimalCoordinate and the marker is shown, however because og the time gap its imposible to press the button at the same time the sms is retrieved and it causes a crash as the data is being sent from the smsreceiver class to nothing on the other side, and if i take the intent out of the onclick method the same thing happens but in reverse, the map runs the intent but the informaion is not there yet and it crashes.
any help would be greatly appreciated as this has been a nightmare.
i am also sorry if i overcomplicated the explanation, i wanted to ake sure it was explained as best i could.
the code is below for the two classes.
Map class
public class MainScreen extends FragmentActivity implements LocationListener {
private GoogleMap map;
private LocationManager locationManager;
private String provider;
final Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_screen);
map = ((SupportMapFragment)getSupportFragmentManager().
findFragmentById(R.id.map)).getMap();
LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean enabledGPS = service
.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean enabledWiFi = service
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
// Check if enabled and if not send user to the GSP settings
if (!enabledGPS) {
Toast.makeText(this, "GPS signal not found", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// Define the criteria how to select the locatioin provider -> use
// default
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
// Initialize the location fields
if (location != null) {
Toast.makeText(this, "Selected Provider " + provider,
Toast.LENGTH_SHORT).show();
onLocationChanged(location);
} else {
//do something
}
// Sets the map type to be "hybrid"
map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
Bundle b = getIntent().getExtras();
double lat = location.getLatitude();
double lng = location.getLongitude();
Toast.makeText(this, "Location " + lat+","+lng,
Toast.LENGTH_LONG).show();
LatLng Usercoordinate = new LatLng(lat, lng);
Marker User = map.addMarker(new MarkerOptions()
.position(Usercoordinate)
.title("You are here")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
//Move the camera instantly to user with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(Usercoordinate, 15));
// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomTo(18), 2000, null);
//Sends sms to 'animal phone'
String phoneNo = "***********";
String sms = "GPSLocation";
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, sms, null, null);
Toast.makeText(getApplicationContext(), "SMS Sent!",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(),
"SMS faild, please try again later!",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
public void map_help(View view) {
//method for the help button
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
context);
// set title
alertDialogBuilder.setTitle("Help");
// set dialog message
alertDialogBuilder
.setMessage("Click the 'Pet' button to display the pets location." +
"This can take a few minutes to retrieve.")
.setCancelable(false)
.setPositiveButton("ok",new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int id) {
// if this button is clicked, close
// current activity
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
};
public void Find_Pet(View view)
{
//String phoneNo = "07516909014";
// String sms = "GPSLocation";
// try {
// SmsManager smsManager = SmsManager.getDefault();
//smsManager.sendTextMessage(phoneNo, null, sms, null, null);
//Toast.makeText(getApplicationContext(), "SMS Sent!",
// Toast.LENGTH_LONG).show();
// } catch (Exception e) {
// Toast.makeText(getApplicationContext(),
// "SMS faild, please try again later!",
//Toast.LENGTH_LONG).show();
// e.printStackTrace();
//}
}
public void Show_Pet(View view)
{
//gets coordinates from SmsReceiver
Bundle b = getIntent().getExtras();
double AnimalLat = b.getDouble("key");
Bundle d = getIntent().getExtras();
double AnimalLon = d.getDouble("key1");
LatLng Animalcoordinate = new LatLng(AnimalLat, AnimalLon);
//adds pets marker on map
Marker Animal = map.addMarker(new MarkerOptions()
.position(Animalcoordinate)
.title("Your pet is here")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
}
/* Request updates at startup */
#Override
protected void onResume() {
super.onResume();
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
/* Remove the locationlistener updates when Activity is paused */
#Override
protected void onPause() {
super.onPause();
locationManager.removeUpdates(this);
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
Toast.makeText(this, "Enabled new provider " + provider,
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(this, "Disabled provider " + provider,
Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
SmsReceiver class
public class SmsReceiver extends BroadcastReceiver
{
String lat = null;
String lon = null;
String message = null;
final SmsReceiver context = this;
#Override
public void onReceive(Context context, Intent intent)
{
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null)
{
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
str += msgs[i].getMessageBody().toString();
}}
message = str.toString();
String[] test = message.split("");
char[] test2 = test[1].toCharArray();
//if the first character of the sms is C then read gps information
if (test2[0] == 'C' || test2[0] =='c')
{
lat = message.substring(45, 56);
lon = message.substring(67, 78);
double AnimalLat=Double.parseDouble(lat);
double AnimalLon=Double.parseDouble(lon);
//Pass coordinates to MainScreen
Intent a = new Intent(getApplicationContext(), MainScreen.class);
Bundle b = new Bundle();
b.putDouble("key", AnimalLat);
a.putExtras(b);
startActivity(a);
Intent c = new Intent(getApplicationContext(), MainScreen.class);
Bundle d = new Bundle();
d.putDouble("key1", AnimalLon);
c.putExtras(d);
startActivity(c);
}else {
}
}
private void startActivity(Intent a) {
// TODO Auto-generated method stub
}
private Context getApplicationContext() {
// TODO Auto-generated method stub
return null;
}}
I also want to apologize for the layout of the code, this is the first time i have pasted code on this site.
Thanks again.
To be honest, I'm not sure which Button you are talking. The only one I saw was in the AlertDialog unless I missed something. Anyway, you can disable your Button until whatever data has a value or you can do nothing in the onClick() if it is null
//inside your Button
if (data != null)
{
...do stuff in here
}
If you need more clarification then please indicate in the code the data you are talking about and the Button but I think you get the idea.

Categories