Last active
August 1, 2022 09:32
-
-
Save FaizanMubasher/095824dd720b24be88f6526128a7ca1b to your computer and use it in GitHub Desktop.
Foreground Location Service
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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())); | |
} | |
} |
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.
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
Hello Sir,
Could you help me? My Android Studio could not see the ServiceUtils. is there any dependency for that?
Thanks!