Skip to content

Instantly share code, notes, and snippets.

@FaizanMubasher
Last active August 1, 2022 09:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FaizanMubasher/095824dd720b24be88f6526128a7ca1b to your computer and use it in GitHub Desktop.
Save FaizanMubasher/095824dd720b24be88f6526128a7ca1b to your computer and use it in GitHub Desktop.
Foreground Location Service
package com.biocare.services;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.location.Location;
import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.biocare.fots.HomeActivity;
import com.biocare.fots.R;
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 LocationTracker extends Service {
public final String TAG = "LocationTracker";
private static final String PACKAGE_NAME =
"com.mypackage.services";
public static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
public static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
public static final String ACTION_START_FOREGROUND_SERVICE =
"ACTION_START_FOREGROUND_SERVICE";
public static final String ACTION_STOP_FOREGROUND_SERVICE =
"ACTION_STOP_FOREGROUND_SERVICE";
/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 30; // Every 15 Seconds
/**
* The fastest rate for active location updates. Updates will never be more frequent
* than this value.
*/
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
public static final String CHANNEL_ID = "my_channel_id";
public static final CharSequence CHANNEL_NAME = "MY Channel";
private LocationRequest mLocationRequest;
/**
* The current location.
*/
private Location mLocation;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
/**
* Callback for changes in location.
*/
private LocationCallback mLocationCallback;
public LocationTracker() {
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "LocationTracker service created");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null){
String action = intent.getAction();
if(action != null) {
switch (action) {
case ACTION_START_FOREGROUND_SERVICE:
startForegroundService();
break;
case ACTION_STOP_FOREGROUND_SERVICE:
stopForegroundService();
break;
}
}
}
return START_STICKY;
}
private void startForegroundService(){
Log.i(TAG, "Start foreground service");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
getLastLocation();
// Create Notification channel
createNotificationChannel();
// Create intent that will bring our app to the front, as if it was tapped in the app
// launcher
Intent showTaskIntent = new Intent(getApplicationContext(), HomeActivity.class);
showTaskIntent.setAction(Intent.ACTION_MAIN);
showTaskIntent.addCategory(Intent.CATEGORY_LAUNCHER);
showTaskIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(
getApplicationContext(),
0,
showTaskIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(getApplicationContext())
.setContentTitle(getString(R.string.app_name))
.setContentText("Location Service is running")
.setSmallIcon(R.drawable.myicon)
.setOnlyAlertOnce(true)
.setWhen(System.currentTimeMillis());
//.setContentIntent(contentIntent);
// Set the Channel ID for Android O.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID); // Channel ID
}
startForeground(1, builder.build());
ServiceUtils.setRequestingLocationUpdates(getApplicationContext(), true);
}
private void stopForegroundService(){
Log.i(TAG, "Stop Foreground Service");
ServiceUtils.setRequestingLocationUpdates(getApplicationContext(), false);
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
// Stop Foreground Service and Remove Notification
stopForeground(true);
// Stop the service
stopSelf();
}
private void createNotificationChannel(){
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if(notificationManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.BLUE);
notificationChannel.setSound(null, null);
notificationChannel.setShowBadge(false);
notificationManager.createNotificationChannel(notificationChannel);
}
}
}
/**
* Sets the location request parameters.
*/
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);
}
private void getLastLocation() {
try {
mFusedLocationClient.getLastLocation()
.addOnCompleteListener(task -> {
if (task.isSuccessful() && task.getResult() != null) {
mLocation = task.getResult();
} else {
Log.w(TAG, "Failed to get location.");
}
});
} catch (SecurityException unlikely) {
Log.e(TAG, "Lost location permission." + unlikely);
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
private void onNewLocation(Location location) {
Log.i(TAG, "New location: " + location);
mLocation = location;
// Notify anyone listening for broadcasts about the new location.
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// You can send Location to Firebase Notitfication for Tracking Purposes
}
}
import android.content.Context;
import android.location.Location;
import android.preference.PreferenceManager;
import com.biocare.fots.R;
import java.text.DateFormat;
import java.util.Date;
public class ServiceUtils {
private static final String KEY_REQUESTING_LOCATION_UPDATES = "requesting_location_updates";
public static final String ACTION_STOP_SERVICE = "stop_location_update";
/**
* Returns true if requesting location updates, otherwise returns false.
*
* @param context The {@link Context}.
*/
public static boolean requestingLocationUpdates(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(KEY_REQUESTING_LOCATION_UPDATES, false);
}
/**
* Stores the location updates state in SharedPreferences.
* @param requestingLocationUpdates The location updates state.
*/
public static void setRequestingLocationUpdates(Context context, boolean requestingLocationUpdates) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putBoolean(KEY_REQUESTING_LOCATION_UPDATES, requestingLocationUpdates)
.apply();
}
/**
* Returns the {@code location} object as a human readable string.
* @param location The {@link Location}.
*/
public static String getLocationText(Location location) {
return location == null ? "Unknown location" :
"(" + location.getLatitude() + ", " + location.getLongitude() + ")";
}
static String getLocationTitle(Context context) {
return context.getString(R.string.location_updated,
DateFormat.getDateTimeInstance().format(new Date()));
}
}
@Begmyrat
Copy link

Hello Sir,
Could you help me? My Android Studio could not see the ServiceUtils. is there any dependency for that?
Thanks!

@FaizanMubasher
Copy link
Author

Function ServiceUtils.setRequestingLocationUpdates(getApplicationContext(), true); just saves the boolean value in shared preferences. You can comment these lines. For your reference, I have updated gist.

@mariodantas
Copy link

Fellow, can you please provide a sample code to instantiate (initialize) your LocationTracker ? start ? stop ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment