Getting GPS location updates while app in the background - android

I have an android application that tracks customer location and send it's location each 10 seconds, however, in android O, location updates will be gotten few times each hour, as said in the documentation about limitation of gps location update in android O. anyway, to overcome this problem, I used a foreground service with notification, so that the gps location update keep updating in fusedLocation.
After that, I faced another problem that speed and direction in fusedLocation are zero, because it takes the location from both network provider and gps provider, when location is from network provider, the speed and direction are zeros, and these info are important for me, and I switched my location service to LocationManager instead of fusedLocation, so I can determine only the gps provider because this feature is not available in fusedLocation.
But what I notice, that LocationManager in android O does not get location updates while in the background even though I use foreground service for that purpose. how can get a solution that keep updating location in background, and use only gps provider?
I don't have a code snipt, I just want to discuss this matter.

Try the below line of code
Write the below line of code in the AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application>
<service
android:name=".LocationTracker"
android:stopWithTask="true"
/>
</application>
Write the line of code from where you want to start service
LocationTracker.startLocationService(getApplicationContext());
Write the below code in service class
public class LocationTracker extends Service{
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
private static int DISPLACEMENT = 0;
private FusedLocationProviderClient mFusedLocationClient;
private LocationRequest mLocationRequest;
private SettingsClient mSettingsClient;
private LocationSettingsRequest mLocationSettingsRequest;
private LocationCallback mLocationCallback;
private String TAG = LocationTracker.class.getSimpleName();
private final int NOTIFICATION_ID = 9083150;
public static final String CHANNEL_ID = "CHANNEL_ID";
public static final String CHANNEL_ID_NAME = "CHANNEL_ID_NAME";
#Override
public void onCreate() {
super.onCreate();
try {
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID_NAME,
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null, null);
channel.setShowBadge(false);
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.deleteNotificationChannel(CHANNEL_ID);
notificationManager.createNotificationChannel(channel);
Notification notification = createNotification(getApplicationContext(),CHANNEL_ID,0);
if (notification == null) {
notification = new NotificationCompat.Builder(this, CHANNEL_ID).build();
}
startForeground(NOTIFICATION_ID, notification);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private Notification createNotification(Context context, String channelid,int type) {
try {
return new NotificationCompat.Builder(context,channelid)
.setContentTitle("")
.setContentText("")
.setOnlyAlertOnce(true)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setSmallIcon(R.mipmap.ic_launcher)
.build();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setLocationUpdateCallback() {
try {
mLocationCallback = null;
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Logger.i(TAG, "locationResult ==== " + locationResult);
}
};
}catch (Exception e){
e.printStackTrace();
}
}
private void init() {
try {
setLocationUpdateCallback();
mFusedLocationClient = null;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = null;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = null;
mLocationSettingsRequest = builder.build();
} catch (SecurityException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
startLocationUpdates();
return START_STICKY;
}
#androidx.annotation.Nullable
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
protected void startLocationUpdates() {
mSettingsClient
.checkLocationSettings(
mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#SuppressLint("MissingPermission")
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.e(TAG, "LocationSettingsStatusCodes onSuccess");
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.e(TAG, "LocationSettingsStatusCodes.RESOLUTION_REQUIRED");
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.e(TAG, "LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE");
}
}
});
}
public static void startLocationService(Context context) {
try {
Intent intent = new Intent(context, LocationTracker.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(context, intent);
} else {
context.startService(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hope it will help for you

Related

Background location updates stopped when app is killed mode

My problem is i can get the location in background but once app is killed it stopped updating.
i am storing the latitude and longitude into firebase once it's fetching from getlastlocation method. and foreground and background mode it's updating fine. but when i close like clearing all the background apps then it is stop updating.
public class MyBackgroundLocationService extends Service {
private static final String TAG = MyBackgroundLocationService.class.getSimpleName();
private FusedLocationProviderClient mLocationClient;
private LocationCallback mLocationCallback;
public MyBackgroundLocationService() {
}
#Override
public void onCreate() {
super.onCreate();
mLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
Log.d(TAG, "onLocationResult: location error");
return;
}
List<Location> locations = locationResult.getLocations();
LocationResultHelper helper = new LocationResultHelper(getApplicationContext(), locations);
helper.showNotification();
helper.saveLocationResults();
Toast.makeText(getApplicationContext(), "Location received: " + locations.size(), Toast.LENGTH_SHORT).show();
}
};
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: called");
startForeground(1001, getNotification());
getLocationUpdates();
return START_STICKY;
}
private Notification getNotification() {
NotificationCompat.Builder notificationBuilder = null;
notificationBuilder = new NotificationCompat.Builder(getApplicationContext(),
App.CHANNEL_ID)
.setContentTitle("Location Notification")
.setContentText("Location service is running in the background.")
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true);
return notificationBuilder.build();
}
private void getLocationUpdates() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(5000);
locationRequest.setFastestInterval(4000);
locationRequest.setMaxWaitTime(15 * 1000);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
stopSelf();
return;
}
mLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, Looper.myLooper());
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: called");
stopForeground(true);
mLocationClient.removeLocationUpdates(mLocationCallback);
}
}
so i am using foreground service to update location in background and it will show in notification those updates. once app is killed notification also disappeared. please please please anyone help me.
if you need more clear about question i will explain. please someone understand my pain

Why app getting crash when It started Waiting for a blocking GC Alloc, When I start my Service?

I'm Starting a Service(location service) at the beginning of app launch. But after staying on the App (approx. 5 to 10 minutes) I'm getting Waiting for a blocking GC Alloc error continuously and my app get stuck for a while then suddenly It crashes.
Also, When I run the app without Service it works smoothly.
I've been searching for many days but nothing solved my problem. I checked many related Q/A over Stack overflow but there are not seems to be any proper or valuable answers.
I also tried by added android:largeHeap="true" in manifests and multiDexEnabled true but these didn't help even.
Here's my Service class
public class LocationService extends IntentService {
private Context context;
private FusedLocationProviderClient fusedLocationClient;
private LocationRequest locationRequest;
Task<LocationSettingsResponse> task;
public static String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp",
CHANNEL_NAME = "My Background Service";
public LocationService() {
super("LocationService");
}
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startMyOwnForeground();
else startForeground(8, new Notification());
createLocationRequest();
context = this;
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
SettingsClient client = LocationServices.getSettingsClient(context);
task = client.checkLocationSettings(builder.build());
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
try {
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
} catch (SecurityException ignore) {
Log.e("AppLocationService", "SecurityException - " + ignore.toString(), ignore);
}
return Service.START_STICKY;
}
private final LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
List<Location> locationList = locationResult.getLocations();
if (locationList.size() != 0) {
Location location = locationList.get(0);
double latitude = location.getLatitude();
double longitude = location.getLongitude();
Intent intent = new Intent("location_update");
intent.putExtra("latitude", lat);
intent.putExtra("longitude", lng);
sendBroadcast(intent);
}
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
}
protected void createLocationRequest() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(2000);
locationRequest.setFastestInterval(2000);
locationRequest.setPriority(CommonObjects.LOCATION_PRIORITY);
}
}
My Logcat

Android periodic location updates using workmanager

I am using a WorkManager as follows -
class LocationWorker(
ctx: Context, params: WorkerParameters
) : CoroutineWorker(ctx, params), KoinComponent {
private val locationDataRepository: LocationDataRepository by inject()
override suspend fun doWork(): Result {
return try {
locationDataRepository.triggerLocationUpdates()
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
I trigger the Worker as -
val myWorker =
PeriodicWorkRequestBuilder<LocationWorker>(
15,
TimeUnit.MINUTES
).addTag(
"location"
).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"location",
ExistingPeriodicWorkPolicy.KEEP,
myWorker
)
As you see, the WorkManager minimum period is 15 minutes. I want to track the location for very short intervals say every few seconds and also I want the location to be tracked even when the phone screen is off. Is WorkManager the right choice for my requirements or would you suggest me some other API?
It might help you it works even when the app is killed..I'm just a tad
concerned when device enters doze mode as gps cannot be accessed when
device is stationary
foreground service main purpose is to run with a persistent notification when the app is killed
LocationService.class
public class LocationService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 30; //30 secs
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
protected static final String TAG = "LocationUpdateService";
public static final int HORIZONTAL_ACCURACY_IN_METERS = 100;
/**
* The identifier for the notification displayed for the foreground service.
*/
private static final int NOTIFICATION_ID = 12345678;
public static boolean mRequestingLocationUpdates = false;
public boolean isEnded = false;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
private SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
private double latitude = 0;
private double longitude = 0;
private float[] results1 = new float[1];
private float distanceInMeters = 0;
private Handler mHandler;
#Override
public void onCreate() {
super.onCreate();
String CHANNEL_ID = "FOREGROUND_CHANNEL";
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"location_notification",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setOngoing(true)
.setContentTitle("G Star")
.setSmallIcon(R.drawable.gm_noti_logo)
.setContentText("Running").build();
startForeground(NOTIFICATION_ID, notification);
Utility.getInstance().makeDescriptiveLogs("ON CREATE WAS HIT");
sendLocationDataToServerPeriodically();
}
private void sendLocationDataToServerPeriodically() {
//getting the alarm manager
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//creating a new intent specifying the broadcast receiver
Intent intentLR = new Intent(this, PostLocationReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intentLR,
PendingIntent.FLAG_UPDATE_CURRENT);
if (android.os.Build.VERSION.SDK_INT >= 23) {
assert am != null;
am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
} else if (Build.VERSION.SDK_INT >= 19) {
if (am != null) {
am.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
}
} else {
if (am != null) {
am.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
isEnded = false;
Utility.getInstance().makeDescriptiveLogs("ONSTART COMMAND WAS HIT");
buildGoogleApiClient();
if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
startLocationUpdates();
}
mHandler = new Handler();
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
if (location.getAccuracy() < HORIZONTAL_ACCURACY_IN_METERS)
updateUI(location);
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
}
/**
* Updates the latitude, the longitude, and the last location time in the UI.
*/
private void updateUI(Location mCurrentLocation) {
mHandler.post(() -> {
/*GET DEVICE CURRENT BATTERY LEVEL*/
int batteryPercent = Utility.getInstance().getBatteryPercentage(LocationService.this);
/* CALCULATE DISTANCE BETWEEN LAT LONG INTERVALS*/
if (latitude != 0 && longitude != 0) {
Location.distanceBetween(latitude, longitude, mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), results1);
distanceInMeters = results1[0];
}
latitude = mCurrentLocation.getLatitude();
longitude = mCurrentLocation.getLongitude();
/*CHECK IF DEVICE HAS ACTIVE INTERNET CONNECTION*/
String networkStatus = Utility.getInstance().checkConnection(LocationService.this) ? "1" : "0";
/*CHECK NETWORK SIGNAL STRENGTH*/
String signalStrength = Utility.getInstance().getSignalStrength(LocationService.this);
SQLiteDBHandler db = SQLiteDBHandler.getInstance(LocationService.this);
db.insertDeviceLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? mCurrentLocation.getSpeedAccuracyMetersPerSecond() : mCurrentLocation.getSpeed(), sdf.format(Calendar.getInstance().getTime()), distanceInMeters, batteryPercent, networkStatus, signalStrength);
});
}
protected void createLocationRequest() {
mGoogleApiClient.connect();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setSmallestDisplacement(5);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Requests location updates from the FusedLocationApi.
*/
public void startLocationUpdates() {
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
isEnded = true;
}
}
/**
* Removes location updates from the FusedLocationApi.
*/
public void stopLocationUpdates() {
if (mRequestingLocationUpdates) {
mRequestingLocationUpdates = false;
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
#Override
public void onDestroy() {
mHandler.removeCallbacksAndMessages(null);
stopLocationUpdates();
super.onDestroy();
}
}
I think that this codelab is the best solution. Without the WorkManager, but for me it works in AccessibilityService ( I realized it like an alternative to ForegroundService) to escape the permanent notification https://codelabs.developers.google.com/codelabs/background-location-updates-android-o/#0

Location Update not working in OPPO, VIVO and MI Phones on Oreo

I am updating the location in the background every 5 minutes.
I checked below code in Android Oreo and above in Samsung and Motorola Devices. It is working fine. But when I checked in MI, OPPO and VIVO, location is not updating if I remove an application from recent task.
I checked this solution but didn't work.
public class GpsTracker extends Service
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks, LocationListener {
final static int REQUEST_LOCATION = 199;
private static final String TAG = GpsTracker.class.getSimpleName();
private static final int PERMISSIONS_REQUEST_PLAYLOCATION = 2000;
private static final int PERMISSIONS_REQUEST_LOCATION = 2001;
public static boolean IS_SERVICE_RUNNING = false;
protected LocationManager locationManager;
private PowerManager pm;
private PowerManager.WakeLock wl;
private Handler handler = new Handler();
private boolean mPlayLocationPermissionGranted;
private boolean mLocationPermissionGranted;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private Location mCurrentLocation;
private LocationTypes locationTypes = LocationTypes.HEARTBEAT;
private GPSTrackerVM gpsTrackerVM;
private boolean noConnect = true;
private Runnable periodicUpdate = new Runnable() {
#Override
public void run() {
handler.postDelayed(periodicUpdate, 5 * 60 * 1000 - SystemClock.elapsedRealtime() % 1000);
// whatever you want to do below
Utils.Log(TAG, "run: Service");
locationTypes = LocationTypes.HEARTBEAT;
buildGoogleApiClient();
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction() != null) {
showNotification();
Utils.Log(TAG, "onStartCommand: " + intent.getAction());
switch (intent.getAction()) {
case AppConfig.ACTION.START_FOREGROUND_ACTION:
Utils.Log(TAG, "Uploading Start");
locationTypes = LocationTypes.HEARTBEAT;
handler.post(periodicUpdate);
break;
case AppConfig.ACTION.START_DAY:
locationTypes = LocationTypes.IN;
buildGoogleApiClient();
break;
case AppConfig.ACTION.END_DAY:
locationTypes = LocationTypes.OUT;
buildGoogleApiClient();
break;
}
}
return START_STICKY;
}
#Override
public void onCreate() {
gpsTrackerVM = new GPSTrackerVM(MyApp.getInstance());
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp:GpsTracker");
wl.acquire();
}
#Override
public void onDestroy() {
IS_SERVICE_RUNNING = false;
super.onDestroy();
wl.release();
}
private void mStopService() {
Utils.Log(TAG, "Sync Stop");
if (handler != null) {
handler.removeCallbacks(periodicUpdate);
}
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
stopForeground(true);
stopSelf();
}
private void showNotification() {
if (!IS_SERVICE_RUNNING) {
String channelId = AppConfig.NOTIFICATION_ID.SYNC_CHANNEL;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channelId = createmNotificationChannel();
}
Intent notificationIntent = new Intent();
notificationIntent.setAction(AppConfig.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_logo_notification);
Notification notification = new NotificationCompat.Builder(this, channelId)
.setContentTitle(getString(R.string.app_name))
.setTicker(getString(R.string.res_sync))
.setContentText(getString(R.string.res_sync))
.setSmallIcon(R.drawable.ic_logo_notification)
.setPriority(Notification.PRIORITY_DEFAULT)
.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(AppConfig.NOTIFICATION_ID.FOREGROUND_SERVICE_SYNC,
notification);
IS_SERVICE_RUNNING = true;
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private String createmNotificationChannel() {
String channelId = AppConfig.NOTIFICATION_ID.SYNC_CHANNEL;
String channelName = AppConfig.NOTIFICATION_ID.SYNC_CHANNEL;
NotificationChannel chan = new NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_DEFAULT);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
service.createNotificationChannel(chan);
return channelId;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public synchronized void buildGoogleApiClient() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
retrieveCurrentLocation();
return;
}
mGoogleApiClient = new GoogleApiClient.Builder(MyApp.getInstance())
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
createLocationRequest();
mGoogleApiClient.connect();
}
public synchronized void stopLocationUpdates() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
// mGoogleApiClient.disconnect();
}
}
private void createLocationRequest() {
long UPDATE_INTERVAL_IN_MILLISECONDS = 100000;
long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
retrieveCurrentLocation();
}
private void retrieveCurrentLocation() {
Log.d(TAG, "retrieveCurrentLocation: 11");
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// get GPS status
boolean checkGPS = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!checkGPS) {
Utils.Log(TAG, "retrieveCurrentLocation: GPS is Off");
updateCurrentLocation(null, "GPS is Turned Off");
return;
}
if (!hasLocationPermissions()) {
Utils.Log(TAG, "retrieveCurrentLocation: Location Permission Denied");
updateCurrentLocation(null, "Location Permission Denied");
return;
}
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient,
builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(#NonNull LocationSettingsResult result) {
mPlayLocationPermissionGranted = false;
final Status status = result.getStatus();
final LocationSettingsStates states = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
mPlayLocationPermissionGranted = true;
requestLocations();
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
mPlayLocationPermissionGranted = false;
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Utils.Log(TAG, "retrieveCurrentLocation: GPS is On, but they need to allow location access from Settings");
updateCurrentLocation(null, "GPS is On, but they need to allow location access from Settings");
break;
}
}
});
}
private void requestLocations() {
Log.d(TAG, "requestLocations: 11");
try {
mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mCurrentLocation == null) {
noConnect = true;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (noConnect) {
updateCurrentLocation(null, "GPS is On, but your device needs one restart to continue locating the device.");
}
}
}, 1000);
}
// updateCurrentLocation(mCurrentLocation);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
} catch (SecurityException ex) {
ex.printStackTrace();
}
}
private boolean hasLocationPermissions() {
if (ActivityCompat.checkSelfPermission(MyApp.getInstance(),
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED
&&
ActivityCompat.checkSelfPermission(MyApp.getInstance(),
Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED
) {
mLocationPermissionGranted = true;
} else {
mLocationPermissionGranted = false;
}
return mLocationPermissionGranted;
}
#Override
public void onLocationChanged(Location location) {
Utils.LogW(TAG, "onLocationChanged: " + location.toString());
if (noConnect) {
noConnect = false;
}
updateCurrentLocation(location, "None");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed: ");
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "onConnectionSuspended: ");
}
public void updateCurrentLocation(Location location, String remark) {
mCurrentLocation = location;
GPSData gpsData = new GPSData(UUID.randomUUID().toString());
gpsData.setLatitude(location == null ? 0 : location.getLatitude());
gpsData.setLongitude(location == null ? 0 : location.getLongitude());
gpsData.setAddress("None");
gpsData.setRemarks(remark);
gpsData.setTimeStamp(System.currentTimeMillis() / 1000L);
gpsData.setLocationType(locationTypes.getValue());
// Log.w(TAG, "updateCurrentLocation: " + location);
stopLocationUpdates();
if (locationTypes == LocationTypes.IN) {
Utils.Log(TAG, "In Success ");
Intent startIntent = new Intent(this, GpsTracker.class);
startIntent.setAction(AppConfig.ACTION.START_FOREGROUND_ACTION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(startIntent);
} else {
startService(startIntent);
}
} else if (locationTypes == LocationTypes.OUT) {
Utils.Log(TAG, "out Success ");
mStopService();
} else if (locationTypes == LocationTypes.HEARTBEAT) {
Utils.Log(TAG, "HEARTBEAT Success ");
}
serverUpdate(gpsData);
}
private void serverUpdate(GPSData gpsData) {
gpsTrackerVM.updateLocation(gpsData);
}
public void onPermissionGrantStatus(boolean isGratned) {
Log.d(TAG, "onPermissionGrantStatus() called with: isGratned = [" + isGratned + "]");
}
}
In AndroidManifest.xml
<service android:name=".services.GpsTracker" />

Use ActivityContext in service for Custom Listner

PrimaryDashBoard where i use LocatinListener and retrieve the location from the service
public class PrimaryDashboard extends AppCompatActivity implements LocationListener {
public LatLng myLatLng=new LatLng(0.0,0.0);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_primary_dashboard);
try {
Intent i = new Intent(this, LocationManager.class);
startService(i);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onLocationChanged(Location location) {
myLatLng=new LatLng(location.getLatitude(),location.getLongitude());
}
#Override
public void GPSDisabled(String errorMessage) {
}
#Override
public void GPSEnabled() {
}
}
Here is LocationListner
public interface LocationListener {
public void onLocationChanged(Location location);
public void GPSDisabled(String errorMessage);
public void GPSEnabled();
}
Here is my Service where i want to initilized the LocationListner and want to update the location values from the listners
public class LocationManager extends IntentService {
private static final String TAG = LocationManager.class.getSimpleName();
// Registered callbacks
public LocationListener locationUpdate;
public static final int REQUEST_CHECK_SETTINGS = 0x1;
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
private FusedLocationProviderClient mFusedLocationClient;
private SettingsClient mSettingsClient;
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private LocationCallback mLocationCallback;
private Location mCurrentLocation;
private Boolean mRequestingLocationUpdates = false;
#SuppressLint("ServiceCast")
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
this.locationUpdate = (LocationListener) getApplicationContext();
mRequestingLocationUpdates = false;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
mSettingsClient = LocationServices.getSettingsClient(getApplicationContext());
createLocationCallback();
createLocationRequest();
buildLocationSettingsRequest();
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
startLocationUpdates();
}
return START_STICKY;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
}
#SuppressLint("ServiceCast")
#Override
public void onCreate() {
super.onCreate();
}
public LocationManager() {
super("locationManager");
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Creates a callback for receiving location events.
*/
private void createLocationCallback() {
mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
mCurrentLocation = locationResult.getLastLocation();
PrefManager.getInstance(getApplicationContext()).setLastLatLng(Double.valueOf(locationResult.getLastLocation().getLatitude()), Double.valueOf(locationResult.getLastLocation().getLongitude()));
if (locationUpdate != null)
locationUpdate.onLocationChanged(locationResult.getLastLocation());
}
};
}
private void buildLocationSettingsRequest() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
}
private void startLocationUpdates() {
// Begin by checking if the device has the necessary location settings.
mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#SuppressLint("MissingPermission")
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
LogCat.show("All location settings are satisfied.");
if (locationUpdate != null)
locationUpdate.GPSEnabled();
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
if (locationUpdate != null)
locationUpdate.GPSDisabled("Location settings are not satisfied. Attempting to upgrade location settings ");
LogCat.show("Location settings are not satisfied. Attempting to upgrade location settings ");
try {
// Show the dialog by calling startResolutionForResult(), and check the
// result in onActivityResult().
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult((Activity) getApplicationContext(), REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException sie) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
String errorMessage = "Location settings are inadequate, and cannot be " +
"fixed here. Fix in Settings.";
LogCat.show(errorMessage);
if (locationUpdate != null)
locationUpdate.GPSDisabled(errorMessage);
Toast.makeText(getApplicationContext(), errorMessage, Toast.LENGTH_LONG).show();
mRequestingLocationUpdates = false;
}
}
});
}
}
This line of code create me a problem because it want Activity context, when it will not be a service and i pass activity Context it works perfect.
this.locationUpdate = (LocationListener) getApplicationContext();
Caused by: java.lang.ClassCastException: android.app.Application cannot be cast to driver.com.driver.LocationComponents.LocationListener
java.lang.RuntimeException: Unable to create service driver.com.driver.LocationComponents.LocationManager: java.lang.ClassCastException: android.app.Application cannot be cast to driver.com.driver.LocationComponents.LocationListener
Firstly , Your application class does not implement the LocationListener interface so your are getting this error. You cannot get the Activity instance inside your intent service , because 1) It may no longer be active 2) Intent Service can be started from other services or broadcast receivers. In order to communicate the LocationListener methods with your activity , you need to use a LocalBroadcastManager.

Categories

Resources