I use a started service with the fused api, and implement the location listener directly on it. The Location keeps updating even when the screen is locked, But it stops if the screen goes off.
So, is there any way to make sure that the location will keep updating when the screen is off?
I read a lot of other questions and I don't really know what i'm missing.
package com.trickyworld.locationupdates;
import android.Manifest;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.model.LatLng;
import java.io.Console;
import java.util.ArrayList;
public class LocationService extends Service {
public static ArrayList<LatLng> locationArrayList = new ArrayList<LatLng>();
FusedLocationProviderClient fusedLocationClient;
LocationRequest locationRequest;
LocationCallback locationCallback;
private void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
fusedLocationClient.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
}
protected void createLocationRequest() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setInterval(3000);
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public void onCreate() {
super.onCreate();
new Notification();
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) createNotificationChanel() ;
else startForeground(
1,
new Notification()
);
locationRequest = LocationRequest.create();
locationRequest.setInterval(2000);
locationRequest.setFastestInterval(2000);
locationRequest.setMaxWaitTime(2000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(#NonNull LocationResult locationResult) {
Location location = locationResult.getLastLocation();
//Toast.makeText(getApplicationContext(),
// "Lat: "+Double.toString(location.getLatitude()) + '\n' +
// "Long: " + Double.toString(location.getLongitude()), Toast.LENGTH_LONG).show();
Log.d("Mesage","Lat: "+Double.toString(location.getLatitude()) + '\n' +
"Long: " + Double.toString(location.getLongitude()));
//locationArrayList.add(new LatLng(location.getLatitude(), location.getLongitude()));
/* for (Location location : locationResult.getLocations()) {
location
}*/
}
};
startLocationUpdates();
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void createNotificationChanel() {
String notificationChannelId = "Location channel id";
String channelName = "Background Service";
NotificationChannel chan = new NotificationChannel(
notificationChannelId,
channelName,
NotificationManager.IMPORTANCE_NONE
);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, notificationChannelId);
Notification notification = notificationBuilder.setOngoing(true)
.setContentTitle("Location updates:")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
fusedLocationClient.removeLocationUpdates(locationCallback);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Related
I am Trying to Build an app where user can show their location and send an SMS to nearby hospital.
I am new to android studio and everything about it, but I quite made a progress with it.
I have 2 XML files, but I'll provide the JAVA CLASSES first
MapActivity.java
package maptesting.app;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CircleOptions;
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 maptesting.app.databinding.ActivityMapBinding;
public class MapActivity<mapView> extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private ActivityMapBinding binding;
private View mapView;
private GoogleMap mMap;
private GoogleApiClient client;
private LocationRequest locationRequest;
private Location lastlocation;
private LocationManager locationManager;
private Marker currentLocationmMarker;
public static final int REQUEST_LOCATION_CODE = 99;
int PROXIMITY_RADIUS = 15000;
double latitude, longitude;
private int LOCATION_MIN_DISTANCE = 20;
private int LOCATION_MIN_TIME = 4000;
private boolean requestingLocationUpdates;
//NEW
private int FINE_LOCATION_REQUEST_CODE = 10001;
private float Geofence_Radius = 4000;
private Object CircleOptions;
//NEW SMS
private LocationListener locationListener;
private final long mTime = 1000;
private final long mDist = 5;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMapBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (!isConnectedToNetwork()) {
Toast.makeText(this, "Turn on mobile data or Wifi", Toast.LENGTH_LONG).show();
finish();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkLocationPermission();
}
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapView = mapFragment.getView();
mapFragment.getMapAsync(this);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (client == null) {
buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
Intent intent = getIntent();
finish();
startActivity(intent);
}
} else {
Toast.makeText(this, "Location Permission Denied", Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onMapReady(#NonNull GoogleMap googleMap) {
mMap = googleMap;
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
// View locationButton = ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
//locationButton.callOnClick();
}
//NEW INPUT (SMS)
LatLng msgloc = new LatLng(lastlocation.getLatitude(), lastlocation.getLongitude());
locationListener = new LocationListener()
{
#Override
public void onLocationChanged(#NonNull Location location)
{
try
{
String phoneNum = "09553625915";
String loc = String.valueOf(msgloc);
String message = "Location = " + msgloc;
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNum, null, message, null, null);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void onProviderEnabled(#NonNull String provider)
{
}
public void onProviderDisabled(#NonNull String provider)
{
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
};
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
try
{
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, mTime, mDist,
(android.location.LocationListener) locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, mTime, mDist,
(android.location.LocationListener) locationListener);
}
catch (SecurityException e)
{
e.printStackTrace();
}
//END NEW INPUT (SMS)
}
private void buildGoogleApiClient() {
client = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
client.connect();
}
#Override
public void onLocationChanged(#NonNull Location location)
{
latitude = location.getLatitude();
longitude = location.getLongitude();
lastlocation = location;
if (currentLocationmMarker != null)
{
currentLocationmMarker.remove();
}
Log.d("lat = ", "" + latitude);
Log.d("lng = ", "" + longitude);
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Location");
AddCircle(latLng, Geofence_Radius);
//markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
//currentLocationmMarker = mMap.addMarker(markerOptions);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
mMap.setMyLocationEnabled(true);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 12));
//mMap.animateCamera(CameraUpdateFactory.zoomBy(2));
//todo delete following lines
Object[] dataTransfer = new Object[2];
getNearbyPlacesData getNearbyPlacesData = new getNearbyPlacesData();
String url = getUrl(latitude, longitude, "hospital");
dataTransfer[0] = mMap;
dataTransfer[1] = url;
getNearbyPlacesData.execute(dataTransfer);
Toast.makeText(MapActivity.this, "Showing Nearby Hospitals", Toast.LENGTH_SHORT).show();
//todo end
if (client != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(client, this);
}
}
private String getUrl(double latitude, double longitude, String nearbyPlace)
{
StringBuilder googlePlaceUrl = new StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
googlePlaceUrl.append("location=" + latitude + "," + longitude);
googlePlaceUrl.append("&radius=" + PROXIMITY_RADIUS);
googlePlaceUrl.append("&type=" + nearbyPlace);
googlePlaceUrl.append("&sensor=true");
//Todo: add your google api key here
googlePlaceUrl.append("&key=" + "YOUR_API_KEY");
Log.d("MapsActivity", "url = " + googlePlaceUrl.toString());
return googlePlaceUrl.toString();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
locationRequest = new LocationRequest();
locationRequest.setInterval(5);
locationRequest.setFastestInterval(500);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// ORG
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(client, locationRequest, this);
}
}
private boolean checkLocationPermission()
{
if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED )
{
if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION))
{
ActivityCompat.requestPermissions(this,new String[] {Manifest.permission.ACCESS_FINE_LOCATION },REQUEST_LOCATION_CODE);
}
else
{
ActivityCompat.requestPermissions(this,new String[] {Manifest.permission.ACCESS_FINE_LOCATION },REQUEST_LOCATION_CODE);
}
return false;
}
else
{
return true;
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
private boolean isConnectedToNetwork() {
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED ||
connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED;
}
// Add Circle
private void AddCircle(LatLng latLng, float radius)
{
mMap.addCircle(new CircleOptions()
.center(latLng)
.radius(Geofence_Radius)
.strokeColor(Color.argb(50, 0, 0, 0))
.fillColor(Color.argb(13,0,0,0))
.strokeWidth(4));
}
What I want to see if its possible to send the user's current location to another phone after I hit the button that will also show their current location in the map.
I am willing to provide the source code if you kind sirs and ma'ams want to check my code.
Thank you
I want to continuously get location updates in the background using service even app is paused I tried much but when the app is paused it won't get any of the user's locations.
Here is my service.java
package com.app.testservices;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
public class MyService extends Service {
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 3000;
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest locationRequest;
private LocationSettingsRequest locationSettingsRequest;
Notification notification;
NotificationCompat.Builder builder;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
prepareNotification(intent);
startLocationUpdates();
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
initData();
}
//Location Callback
private LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Location currentLocation = locationResult.getLastLocation();
Log.d("Locations", currentLocation.getLatitude() + "," + currentLocation.getLongitude());
//Share/Publish Location
builder.setContentText(currentLocation.getLatitude() + "," + currentLocation.getLongitude());
Notification nm = builder.build();
startForeground(2, nm);
}
};
private void startLocationUpdates() {
mFusedLocationClient.requestLocationUpdates(this.locationRequest,
this.locationCallback, Looper.getMainLooper());
}
public void prepareNotification(Intent intent) {
String input = intent.getStringExtra("input");
Intent notificationIntent = new Intent(this, MyService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
builder = new NotificationCompat.Builder(this, MyChannel.CHANNEL_ID)
.setContentTitle("My notification")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android_black_24dp)
.setContentIntent(pendingIntent);
notification = builder.build();
startForeground(1, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("restartservice");
broadcastIntent.setClass(this, Restarter.class);
this.sendBroadcast(broadcastIntent);
}
private void initData() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setNumUpdates(Integer.MAX_VALUE);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
}
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 10,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
}
Channel.java
package com.app.testservices;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;
public class MyChannel extends Application {
public static final String CHANNEL_ID = "serviceChannel";
#Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Notification service",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
I also tried to write a restarter to restart the service to fetch the location Restarter.java
package com.app.testservices;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
public class Restarter extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Broadcast Listened", "Service tried to stop");
Toast.makeText(context, "Service restarted", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, MyService.class));
} else {
context.startService(new Intent(context, MyService.class));
}
}
}
Here is my MainActivity.java
package com.app.testservices;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Looper;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
public class MainActivity extends AppCompatActivity {
private EditText etInput;
protected static final int REQUEST_CHECK_SETTINGS = 0x1;
FusedLocationProviderClient mFusedLocationClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etInput = findViewById(R.id.et_input_text);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, 1);
return;
}
}
public void startService(View view) {
String input = etInput.getText().toString();
Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("input", input);
startService(serviceIntent);
}
public void stopService(View view) {
Intent serviceIntent = new Intent(this, MyService.class);
stopService(serviceIntent);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
// If request is cancelled, the result arrays are empty.
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
Location location = task.getResult();
LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
if (location == null) {
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5);
mLocationRequest.setFastestInterval(0);
mLocationRequest.setNumUpdates(2);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, 1);
return;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
} else {
System.out.println("Location: " + location);
}
}
});
}
}
}
public void enableLocationSettings() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
LocationRequest locationRequest = LocationRequest.create()
.setInterval(5)
.setFastestInterval(0)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
LocationServices.getSettingsClient(this).checkLocationSettings(builder.build())
.addOnSuccessListener(this, (LocationSettingsResponse response) -> {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.getLastLocation().addOnCompleteListener(task -> {
Location location = task.getResult();
LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
if (location == null) {
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5);
mLocationRequest.setFastestInterval(0);
mLocationRequest.setNumUpdates(2);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(MainActivity.this);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
}, 1);
return;
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
} else {
System.out.println("Location: " + location);
}
});
}
}).addOnFailureListener(this, ex -> {
if (ex instanceof ResolvableApiException) {
// Location settings are NOT satisfied, but this can be fixed by showing the user a dialog.
try {
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 1);
ResolvableApiException resolvable = (ResolvableApiException) ex;
resolvable.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sendEx) {
// Ignore the error.
}
}
});
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (REQUEST_CHECK_SETTINGS == requestCode) {
if (Activity.RESULT_OK == resultCode) {
}
}
}
}
Any help or guidance will be appreciated. Moreover,
I also tried Android How to get user location continuously even your app is killed
this but it didn't work for me.
You need to keep a foreground service always running. You need to start it when the app is in the foreground and then keep it running all the time even when the app is in the background.
You should use a Foreground Service with a partial wakelock, in order to prevent the phone from sleeping.
Here below an example of Foreground Service Class that implements a Wakelock:
public class ICService extends Service {
private static final int ID = 1; // The id of the notification
private NotificationCompat.Builder builder;
private NotificationManager mNotificationManager;
private PowerManager.WakeLock wakeLock; // PARTIAL_WAKELOCK
/**
* Returns the instance of the service
*/
public class LocalBinder extends Binder {
public ICService getServiceInstance(){
return ICService.this;
}
}
private final IBinder mBinder = new LocalBinder(); // IBinder
#Override
public void onCreate() {
super.onCreate();
// PARTIAL_WAKELOCK
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"INSERT_YOUR_APP_NAME:wakelock");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
startForeground(ID, getNotification());
return START_NOT_STICKY;
}
#SuppressLint("WakelockTimeout")
#Override
public IBinder onBind(Intent intent) {
if (wakeLock != null && !wakeLock.isHeld()) {
wakeLock.acquire();
}
return mBinder;
}
#Override
public void onDestroy() {
// PARTIAL_WAKELOCK
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
}
super.onDestroy();
}
private Notification getNotification() {
final String CHANNEL_ID = "YOUR_SERVICE_CHANNEL";
builder = new NotificationCompat.Builder(this, CHANNEL_ID);
//builder.setSmallIcon(R.drawable.ic_notification_24dp)
builder.setSmallIcon(R.mipmap.YOUR_RESOURCE_ICON)
.setColor(getResources().getColor(R.color.colorPrimaryLight))
.setContentTitle(getString(R.string.app_name))
.setShowWhen(false)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setOngoing(true)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentText(composeContentText());
final Intent startIntent = new Intent(getApplicationContext(), ICActivity.class);
startIntent.setAction(Intent.ACTION_MAIN);
startIntent.addCategory(Intent.CATEGORY_LAUNCHER);
startIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 1, startIntent, 0);
builder.setContentIntent(contentIntent);
return builder.build();
}
}
Obviously you still have also to disable battery optimization for your app.
You can browse a real working example of this service on a GPS Logging app here.
Don't forget to declare your service type as "location" into your AndroidManifest.xml, in order to allow your application to receive the GPS updates also after a momentary signal loss when running in background, and to add the FOREGROUND_SERVICE and WAKE_LOCK permissions:
In your manifest you should declare:
...
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
...
<!-- Recommended for Android 9 (API level 28) and lower. -->
<!-- Required for Android 10 (API level 29) and higher. -->
<service
android:name="MyGPSService"
android:foregroundServiceType="location" ... >
</service>
...
As a note, if the location requests start when the app is in the foreground, you don't need to request the android.permission.ACCESS_BACKGROUND_LOCATION permission to continue to receive locations in background, also in case of momentary signal loss. the android.permission.ACCESS_FINE_LOCATION (and, if you target API31, also android.permission.ACCESS_COARSE_LOCATION) is enough for your use.
I'm getting
java.lang.ClassCastException: com.example.BellasHBG.LocationService cannot be cast to com.google.android.gms.location.LocationListener
but I don't know how to resolve. Removing keyword abstract does not fix the problem. This is new to me, and I'm not that knowledgeable of java so any help is appreciated. The error seems top be occurring in LocationService on the following line: LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mlocationRequest, (com.google.android.gms.location.LocationListener) this);
The intent is to get location updates and send a notification to the app user if the location sells this particular bakery product.
Below are my MainActivity, LocationService and AndroidManifest.xml
MainActivity
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.view.KeyEvent;
import android.webkit.WebViewClient;
import android.widget.TextView;
import com.google.android.gms.location.LocationRequest;
//import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private WebView webView = null;
public static boolean orignotifsetting = false;
//PendingIntent pendingIntent;
private Alarm alarm;
MyToolBox mtools = new MyToolBox();
LocationIntentService mLocationIntentService = new LocationIntentService();
public LocationManager mlocManager;
//LocationListener mlocListener = new MyLocationListener();
//LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//public static GoogleApiClient mGoogleApiClient;
private Location mCurrentLocation;
LocationRequest mLocationRequest;
PendingIntent resultPendingIntent;
public Intent resultIntent = new Intent();
LocationServiceImpl mLocationService = new LocationServiceImpl();
public static boolean prevNotificationsSetting;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("myTag", "in onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//set the default values first time run but don't overwrite them if they have been set
// ----------------------------------------------------------------| - true will leave them alone, false will clear them every time
PreferenceManager.setDefaultValues(this, R.xml.pref_notification, true);
this.webView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
//myWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
//myWebView.setWebViewClient(new WebViewClient());
WebViewClientImpl webViewClient = new WebViewClientImpl(this);
webView.setWebViewClient(webViewClient);
webView.loadUrl("https://www.bellashbg.com");
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && this.webView.canGoBack()) {
this.webView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public void onResume() {
Log.i("myTag", "in onResume");
super.onResume();
Intent msgIntent = new Intent(MainActivity.this, LocationService.class);
if ((mtools.notificationsSetting(this)) & (prevNotificationsSetting == false)) {
prevNotificationsSetting = true;
startService(msgIntent);
}
else {
if ((!mtools.notificationsSetting(this)) & (prevNotificationsSetting == true)) {
// mLocationService.stopLocationUpdates();
prevNotificationsSetting = false;
boolean result = stopService(msgIntent);
if (result){
Log.d("MainActivity", "stopService true");
}
else {
Log.d("MainActivity", "stopService false");
}
//mLocationService.stopLocationUpdates();
//android.os.Process.killProcess(android.os.Process.myPid());
}
}
}
#Override
public void onPause() {
Log.i("myTag", "in onPause");
super.onPause();
}
#Override
public void onStop() {
Log.i("myTag", "in onStop");
super.onStop();
}
public void onDestroy() {
Log.i("myTag", "in onDestroy");
super.onDestroy();
//if (mSensorManager!=null){mSensorManager.unregisterListener(listener);}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i("myTag", "in onCreateOptionsMenu");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.settings_menu, menu);
return super.onCreateOptionsMenu(menu); // cmnted 10/25/2015
//super.onCreateOptionsMenu(menu);
//return true;
// return true; stack overflow 6439085 says to return true to pop up menu
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.i("myTag", "in onOptionsItemSelected");
//LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); //added 11/12/2015 to remove updates
switch (item.getItemId()) {
case R.id.settings:
Intent settingsintent = new Intent(MainActivity.this, SettingsActivity.class);
MainActivity.this.startActivity(settingsintent);
break;
case R.id.help:
break;
case R.id.about:
break;
}
return true;
}
// Get the notifications status bar setting
public boolean notificationsSettingNotificationBar() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
boolean notificationsNewMessageNotificationBar = SP.getBoolean("notifications_new_message_notification_bar", true);
return notificationsNewMessageNotificationBar;
}
// Get the notifications ringtone
public String notificationsSettingRingtone() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String notificationsNewMessageRingtone = SP.getString("notifications_new_message_ringtone", "NULL");
return notificationsNewMessageRingtone;
}
// Get the notifications vibrate setting
public boolean notificationsNewMessageSetting() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
boolean notificationNewMessageVibrate = SP.getBoolean("notifications_new_message_vibrate", true);
return notificationNewMessageVibrate;
}
private TextView latituteField;
private Context mContext;
}
LocationService
package com.example.BellasHBG;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;
import androidx.core.app.TaskStackBuilder;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
//import com.google.android.gms.location.LocationListener;
//import android.support.v7.app.AppCompatActivity;
//import android.support.v4.app.NotificationCompat;
//import android.support.v4.app.TaskStackBuilder;
//import com.google.android.gms.common.ConnectionResult;
//import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
//import com.google.android.gms.location.LocationListener;
//import com.google.android.gms.location.LocationRequest;
//import com.google.android.gms.location.LocationServices;
/**
* Created by craigmartensen on 4/7/16.
*/
public abstract class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 60000 * 1; // 1000 milliseconds in 1 second
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 5;
public static final long LOCATION_DISTANCE_IN_METERS = 3;
MyToolBox mtools = new MyToolBox();
public static GoogleApiClient mGoogleApiClient;
//public static GoogleSignInClient mSignInClient;
public static GoogleSignInAccount mSignInClient;
LocationRequest mlocationRequest;
private boolean isRemoving = false;
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#SuppressWarnings("static-access")
#Override
public void onCreate() {
isRemoving = false;
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
//alarm.SetAlarm(this);
//return START_STICKY;
super.onStartCommand(intent, flags, startId);
//Toast.makeText(this, "onHandleIntent", Toast.LENGTH_SHORT).show();
//mGoogleApiClient.connect();
Log.d("onStartCommand", "Service Started");
return Service.START_STICKY;
}
#Override
public void onConnected(Bundle connectionHint) {
if (isRemoving) {
stopLocationUpdates();
}
else {
isRemoving = false;
mlocationRequest = new LocationRequest();
mlocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mlocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mlocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mlocationRequest.setSmallestDisplacement(LOCATION_DISTANCE_IN_METERS);
Intent locationIntent = new Intent(getApplicationContext(), LocationIntentService.class);
locationIntent.putExtra("ID", "FusedLcation");
PendingIntent locationPendingIntent = PendingIntent.getService(getApplicationContext(), 0, locationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mlocationRequest, locationPendingIntent);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mlocationRequest, (com.google.android.gms.location.LocationListener) this);
}
}
public void onLocationChanged(Location loc)
{
Log.d("onLocationChanged", "Entering method");
//Toast.makeText(this, "onLocationChanged", Toast.LENGTH_SHORT).show();
mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
//Toast.makeText(getApplicationContext(), "entering onLocationChanged", Toast.LENGTH_SHORT).show();
String myText;
double mlat = loc.getLatitude();
double mlong = loc.getLongitude();
DBHelper myDBHelper = new DBHelper(this);
// use the following line if you just want to know if the location is found ie, sells Bellas
//boolean soldHere = myDBHelper.doesLocationSellBellas("my_table",41.685471,-73.975393);
// the following line retrieves the name of the location that sells bellas, null if it's not found
//String locName = myDBHelper.getLocationName("my_table", 41.685471, -73.975393);
String locName = myDBHelper.getLocationName(DBHelper.LOCATION_TABLE_NAME, mlat, mlong);
// set up for notification in the notification status bar
if (locName != null) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Bella's sold here");
// .setStyle(new NotificationCompat.BigTextStyle().bigText("Bella's sold here"));
// .setSubText(todaysjolt);
// .setDefaults(Notification.DEFAULT_SOUND)
//.setContentText("Bella's sold here");
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mBuilder.setContentText(locName);
mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(locName));
// new 10/14/2015 - set up to allow user to go to website from notification
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
// end new 10/14/2015
mNotifyMgr.notify(000, mBuilder.build());
Toast.makeText(getApplicationContext(), "You are at " + locName, Toast.LENGTH_SHORT).show();
//LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
}
protected void startLocationUpdates() {
if (mtools.notificationsSetting(this)) {
MainActivity.orignotifsetting = true;
//LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
public void stopLocationUpdates() {
if(!mGoogleApiClient.isConnected()){
isRemoving = true; //added
mGoogleApiClient.connect();
}
else {
//if (mGoogleApiClient != null) {
// if (!mGoogleApiClient.isConnected()) {
PendingIntent locationPendingIntent = PendingIntent.getService(this, 0, new Intent(this, LocationIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
//LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, locationPendingIntent); //moved below 1/28/2016
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, (com.google.android.gms.location.LocationListener) com.example.BellasHBG.LocationService.this);
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
stopSelf(); // stop the service
}
//}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this, "Connection Failed", Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionSuspended(int i) {
Log.d("LocationUpdateService", "Connection Suspended");
}
#Override
public void onDestroy(){
stopLocationUpdates();
//reportarGPS.interrupt();
//reportarGPS = null;
//LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, (com.google.android.gms.location.LocationListener) this);
//mGoogleApiClient.disconnect();
//mGoogleApiClient = null;
//mHandler.removeCallbacksAndMessages(null);
//Thread.currentThread().interrupt();
super.onDestroy();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.BellasHBG">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="21"/>
<application
android:allowBackup="true"
android:icon="#drawable/bellas_logo_48x36"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.BellasHBG"
android:usesCleartextTraffic="true">
<activity
android:name="com.example.BellasHBG.SettingsActivity"
android:label="#string/action_settings"/>
<activity
android:name="com.example.BellasHBG.CreateNotificationOnBar"
android:label="create_notification_on_bar"/>
<activity
android:name="com.example.BellasHBG.CustomPreference"
android:label="custom_preference"/>
<activity
android:name=".MainActivity"
android:label="Bella's Home Baked Goods" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.example.BellasHBG.Alarm" />
<service android:enabled='true' android:name="com.example.BellasHBG.LocationService" />
</application>
</manifest>
Please uncomment the import for com.google.android.gms.location.LocationListener on LocationService and give a try again.
I am trying to get location after every 10 second using FusedLocationProviderClient, However when i minimize the app or terminate it the location updates stops. Below is my code. Right now i am using android 9.0. I have no idea why this is happening any help will be grateful
Android Menifest
<service android:enabled="true" android:name=".LocationService">
</service>
LocationService.java
package com.example.locationupdate;
import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.example.locationupdate.db.Realm$Helper;
import com.example.locationupdate.shared_pref.SaveInSharedPreference;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.SettingsClient;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import java.util.List;
import static com.google.android.gms.location.LocationServices.getFusedLocationProviderClient;
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
//private LocationRequest mLocationRequest;
private long UPDATE_INTERVAL = 10 * 1000; /* 10 secs */
private long FASTEST_INTERVAL = 2000;
int count = 0;
List<FilterData> datafromDB;
FusedLocationProviderClient mFusedLocationClient;
LocationRequest mLocationRequest;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
LocationCallback mLocationCallback = new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
//Log.e("MainActivity", "Location: " + location.getLatitude() + " " + location.getLongitude());
if (SaveInSharedPreference.getInSharedPreference(LocationService.this).getLat() == 0.0 && SaveInSharedPreference.getInSharedPreference(LocationService.this).getLng() == 0.0) {
SaveInSharedPreference.getInSharedPreference(LocationService.this).setLatLong(location.getLatitude(), location.getLongitude());
}
SaveInSharedPreference.getInSharedPreference(LocationService.this).setCurrentLatLong(location.getLatitude(), location.getLongitude());
count = count + 1;
Log.e("mLocationCallbackLat", String.valueOf(location.getLatitude()));
Log.e("mLocationCallbackLong", String.valueOf(location.getLongitude()));
//LocationMatch(location);
}
/* datafromDB = Realm$Helper.getLocation$Module(LocationService.this).getAllData();
for (FilterData str : datafromDB) {
String name = str.getName();
}*/
};
};
public void onResume() {
Log.e("OnResume", "OnResumeEvent");
if (mFusedLocationClient != null) {
requestLocationUpdates();
}
}
public void requestLocationUpdates() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL); // two minute interval
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
}
public void onPause() {
//super.onPause();
Log.e("ONPause", "OnPauseEvent");
if (mFusedLocationClient != null) {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
}
protected void startLocationUpdates() {
// Create the location request to start receiving updates
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
// Create LocationSettingsRequest object using location request
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Check whether location settings are satisfied
// https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
settingsClient.checkLocationSettings(locationSettingsRequest);
// new Google API SDK v11 uses getFusedLocationProviderClient(this)
getFusedLocationProviderClient(this).requestLocationUpdates(mLocationRequest, new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
// do work here
onLocationChanged(locationResult.getLastLocation());
}
},
Looper.myLooper());
}
public void onLocationChanged(Location location) {
if (SaveInSharedPreference.getInSharedPreference(LocationService.this).getLat() == 0.0 && SaveInSharedPreference.getInSharedPreference(LocationService.this).getLng() == 0.0) {
SaveInSharedPreference.getInSharedPreference(LocationService.this).setLatLong(location.getLatitude(), location.getLongitude());
}
SaveInSharedPreference.getInSharedPreference(LocationService.this).setCurrentLatLong(location.getLatitude(), location.getLongitude());
Toast.makeText(this,"onLocationChanged",Toast.LENGTH_LONG);
// New location has now been determined
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.e ("onLocationChangedLat", String.valueOf(location.getLatitude()));
Log.e ("onLocationChangedLong", String.valueOf(location.getLongitude()));
// You can now create a LatLng Object for use with maps
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
/*loc1.setLatitude(location.getLatitude());
loc1.setLongitude(location.getLongitude());
loc2.setLatitude(str.getLat());
loc2.setLongitude(str.getlng());
double distanceInMeters = loc1.distanceTo(loc2);
Log.e("Name", name);
Log.e("Distance", "" + distanceInMeters);*/
}
public void getLastLocation() {
// Get last known recent location using new Google Play Services SDK (v11+)
FusedLocationProviderClient locationClient = getFusedLocationProviderClient(this);
locationClient.getLastLocation()
.addOnSuccessListener(new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
// GPS location can be null if GPS is switched off
if (location != null) {
onLocationChanged(location);
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("MapDemoActivity", "Error trying to get last GPS location");
e.printStackTrace();
}
});
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
MainActitvity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//locationTv = findViewById(R.id.location);
Intent startIntent = new Intent(this, LocationService.class);
startService(startIntent);
You can achieve this by setting up a handler and adding the required permissions to the android app. Apperantly there is a limit to how many times you can request the location in the background according to Android Location In Background but i have not seen this. Im requesting a new location every second.
First add these to your manifest:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Then you can create a handler like this.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
createLocationHandler();
...
}
The createLocationHandler and isServiceRunning function:
public void createLocationHandler(){
HandlerThread locationHandler = new HandlerThread("LocationHandler"); //Creates a new handler thread
locationHandler.start(); //Starts the thread
Handler handler = new Handler(locationHandler.getLooper()); //Get the looper from the handler thread
handler.postDelayed(new Runnable() {//Run the runnable only after the given time
#Override
public void run() {
//Check if the location service is running, if its not. lets start it!
if(!isMyServiceRunning(LocationService.class)){
getApplicationContext().startService(new Intent(getApplicationContext(), LocationService.class));
}
//Requests a new location from the location service(Feel like it could be done in a less static way)
LocationService.requestNewLocation();
createLocationHandler();//Call the create location handler again, this will not be added to the stack because of the looper.
}
}, 10000);//Set the delay to be 10 seconds, 1 second = 1000 milliseconds
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) this.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Remember to ask for the background_location permission before you want to start the service.
I'm having trouble trying to get the latitude and longitude from my Service and store them as variables so I can access them from other classes I'm building. I want to have them equal to the current latitude and longitude of the user and update them through the interval set in the requestLocation() method. I would like to store them as variables as I would like to perform some calculations using them and I have also written a Content Provider/Database Helper in order to store them in my local Sqlite database but can't right now as I cannot access them. Below can be seen my code for my Location service and MainActivity.
Location Service
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
public class LocationService extends Service {
FusedLocationProviderClient fusedLocationProviderClient;
LocationCallback locationCallback;
private final IBinder binder = new LocalBinder();
//public double latitude;
//public double longitude;
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
super.onCreate();
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationCallback = new LocationCallback(){
// Whenever there is a Location Update, this method is where it occurs
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
// Log Result for Longitude and Latitude, call method to receive elsewhere
Log.d("myLog", "Latitude is: " + locationResult.getLastLocation().getLatitude() + ", " +
"Longitude is: " + locationResult.getLastLocation().getLongitude());
Intent intent = new Intent("ACT_LOC");
intent.putExtra("Latitude", locationResult.getLastLocation().getLatitude());
intent.putExtra("Longitude", locationResult.getLastLocation().getLongitude());
sendBroadcast(intent);
//double latitude = locationResult.getLastLocation().getLatitude();
//double longitude = locationResult.getLastLocation().getLongitude();
}
};
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
requestLocation();
return super.onStartCommand(intent, flags, startId);
}
// Method to request the Location every 3 seconds
private void requestLocation(){
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(3000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
}
public class LocalBinder extends Binder {
LocationService getService(){
return LocationService.this;
}
}
}
MainActivity
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 23) {
// If the permission Access Fine Location is not granted
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// Request permissions again
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
} else {
// Start Location Service
startService();
}
} else {
// Start Location Service
startService();
}
}
// Start the service with a new intent for the MainActivity and Location Services
// Register Broadcast Receiver with intent action from LocationService.java
void startService() {
LocationBroadcastReceiver receiver = new LocationBroadcastReceiver();
IntentFilter filter = new IntentFilter("ACT_LOC");
Intent intent = new Intent(this, LocationService.class);
registerReceiver(receiver, filter);
startService(intent);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startService();
} else {
Toast.makeText(this, "Permissions Required", Toast.LENGTH_LONG).show();
}
}
}
public class LocationBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// check if action is required or not
if (intent.getAction().equals("ACT_LOC")) {
double lat = intent.getDoubleExtra("Latitude", 0f);
double lng = intent.getDoubleExtra("Longitude", 0f);
Toast.makeText(MainActivity.this, "Latitude is: " + lat + ", Longitude is: " + lng, Toast.LENGTH_LONG).show();
}
}
}
}