Skip to content

Instantly share code, notes, and snippets.

@ericbrunner
Created June 4, 2017 05:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericbrunner/d13270abd26f2130fc397609b89fc3ef to your computer and use it in GitHub Desktop.
Save ericbrunner/d13270abd26f2130fc397609b89fc3ef to your computer and use it in GitHub Desktop.
GpsTrackerService
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.OS;
using System.Threading;
using System.Threading.Tasks;
using Plugin.Connectivity;
using trucker_rolsped.Models;
using Android.Media;
using Android.Provider;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Telephony;
using Android.Util;
using HockeyApp.Android.Metrics;
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Plugin.Geolocator;
using trucker_rolsped.GeoLocation;
using trucker_rolsped.StoreManager;
namespace trucker_rolsped.Droid.GeoLocation
{
[Service]
public class GpsTrackerService : Service
{
private static readonly string LogTag = "X:TruckerApp-" + typeof(GpsTrackerService).Name;
private static readonly int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
private static readonly int GPS_NOT_ENABLED_NOTIFICATION_ID = 10001;
private MobileServiceClient _mobileServiceClient;
private PowerManager.WakeLock _cpuWakeLock;
public TelephonyManager GetTelefonyManager()
{
return (Android.Telephony.TelephonyManager) GetSystemService(TelephonyService);
}
public bool IsRunningAsService { get; set; }
public override async void OnCreate()
{
base.OnCreate();
try
{
// keep CPU on even when screen is off. see: https://developer.android.com/training/scheduling/wakelock.html#cpu
PowerManager pm = (PowerManager) GetSystemService(PowerService);
_cpuWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GpsTrackerServiceWakeLock");
_cpuWakeLock.Acquire();
if (MainActivity.CurrentActivity == null)
{
Log.Debug(LogTag, "GpsTrackerService.OnCreate :: -------- SERVICE IS RUNNING ---------");
IsRunningAsService = true;
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnCreate :: -------- SERVICE IS RUNNING ---------");
MetricsManager.Register(Application, MainActivity.HockeyAppId);
const string imeiKey = "imei";
var telefonyManager = GetTelefonyManager();
if (telefonyManager == null)
{
Log.Debug(LogTag, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) telefonyManager == null");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) IMEI == null.");
return;
}
//IMEI number
String imei = telefonyManager.DeviceId;
if (imei == null)
{
Log.Debug(LogTag, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) IMEI == null");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) IMEI == null.");
return;
}
Log.Debug(LogTag, $"GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) IMEI == {imei}");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, $"GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) IMEI == {imei}");
JObject credentials = new JObject
{
[imeiKey] = imei
};
_mobileServiceClient = new MobileServiceClient(trucker_rolsped.Helper.Constants.AppServiceUrl);
if (_mobileServiceClient == null)
{
Log.Debug(LogTag, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) _mobileServiceClient == null.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) _mobileServiceClient == null.");
return;
}
await _mobileServiceClient.LoginAsync("custom", credentials);
if (_mobileServiceClient.CurrentUser == null)
{
Log.Debug(LogTag, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) ZUMO USER still == null.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) ZUMO USER still == null.");
return;
}
Log.Debug(LogTag, $"GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) ZUMO USER {_mobileServiceClient.CurrentUser.UserId}");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, $"GpsTrackerService.OnCreate :: (SERVICE IS RUNNING) ZUMO USER {_mobileServiceClient.CurrentUser.UserId}");
}
else
{
// When App is running
Log.Debug(LogTag, "GpsTrackerService.OnCreate :: +++++++++ APP IS RUNNING ++++++++++");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnCreate :: +++++++++ APP IS RUNNING ++++++++++");
_mobileServiceClient = OfflineSyncStoreManager.Instance.MobileAppClient;
Log.Debug(LogTag, $"GpsTrackerService.OnCreate :: (APP IS RUNNING) ZUMO USER {_mobileServiceClient?.CurrentUser?.UserId}");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, $"GpsTrackerService.OnCreate :: (APP IS RUNNING) ZUMO USER {_mobileServiceClient?.CurrentUser?.UserId}");
}
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.OnCreate :: Exception:{e.Message} Type:{e.GetType().Name}");
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
finally
{
_cpuWakeLock.Release();
}
}
void RegisterForegroundService()
{
var notification = new NotificationCompat.Builder(this)
.SetContentTitle("TruckerApp GPS Service")
.SetContentText("TruckerApp GPS Service running ...")
.SetTicker("TruckerApp GPS Service")
.SetSmallIcon(Resource.Drawable.ic_launcher)
.SetContentIntent(BuildIntentToShowMainActivity())
.SetOngoing(true)
.AddAction(BuildStopServiceAction())
.Build();
// Enlist this instance of the service as a foreground service
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
}
/// <summary>
/// Builds a PendingIntent that will display the main activity of the app. This is used when the
/// user taps on the notification; it will take them to the main activity of the app.
/// </summary>
/// <returns>The content intent.</returns>
PendingIntent BuildIntentToShowMainActivity()
{
var notificationIntent = new Intent(this, typeof(MainActivity));
notificationIntent.SetFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTask);
var pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.UpdateCurrent);
return pendingIntent;
}
/// <summary>
/// Builds the Notification.Action that will allow the user to stop the service via the
/// notification in the status bar
/// </summary>
/// <returns>The stop service action.</returns>
NotificationCompat.Action BuildStopServiceAction()
{
var stopServiceIntent = new Intent(this, GetType());
stopServiceIntent.SetAction(GpsConstants.ACTION_STOP_SERVICE);
var stopServicePendingIntent = PendingIntent.GetService(this, 0, stopServiceIntent, 0);
var builder = new NotificationCompat.Action.Builder(Android.Resource.Drawable.IcMediaPause,
"Stop",
stopServicePendingIntent);
return builder.Build();
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
base.OnStartCommand(intent, flags, startId);
if (intent.Action != null && intent.Action.Equals(GpsConstants.ACTION_STOP_SERVICE))
{
try
{
Log.Info(LogTag, "GpsTrackerService.OnStartCommand :: The service is stopping.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnStartCommand :: The service is stopping.");
StopForeground(true);
StopSelf();
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.OnStartCommand :: (ACTION_STOP_SERVICE branch) Exception:{e.Message} Type:{e.GetType().Name}");
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
}
else
{
try
{
_cpuWakeLock.Acquire();
RegisterForegroundService();
Log.Debug(LogTag, "GpsTrackerService.OnStartCommand :: Service started.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnStartCommand :: Service started.");
Task.Run(async () =>
{
try
{
await DoWork();
await Task.Delay(TimeSpan.FromMinutes(2));
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.HandleTimerCallback :: (OUTER try-catch) Exception:{e.Message} Type:{e.GetType().Name}, Stacktrack:{e.StackTrace}");
if (e.InnerException != null)
{
Log.Debug(LogTag, $"GpsTrackerService.HandleTimerCallback :: (OUTER try-catch) Exception:{e.InnerException.Message} Type:{e.InnerException.GetType().Name}, Stacktrack:{e.InnerException.StackTrace}");
}
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
finally
{
// Restart Service
Intent broadcastIntent = new Intent(action: GpsConstants.GpsRestart);
SendBroadcast(broadcastIntent);
try
{
_cpuWakeLock.Release();
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.OnStartCommand :: (_cpuWakeLock.Release) Exception:{e.Message} Type:{e.GetType().Name}");
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
}
});
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.OnStartCommand :: (DoWork branch) Exception:{e.Message} Type:{e.GetType().Name}");
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
}
return StartCommandResult.Sticky;
}
public bool IsWorkingDayTime()
{
var now = DateTime.Now;
return (now.DayOfWeek != DayOfWeek.Saturday || now.DayOfWeek != DayOfWeek.Sunday) && (now.Hour > 4 && now.Hour < 21);
}
public async Task DoWork()
{
// long running code ...
Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: Invoked.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: Invoked.");
if (CrossConnectivity.Current.IsConnected)
{
//if (!IsWorkingDayTime())
//{
// Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: Skip Gps data tracking out of business time (Sat,Sun, 21 p.m - 4 a.m.).");
// GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: Skip Gps data tracking out of business time (Sat,Sun, 21 p.m - 4 a.m.).");
// return;
//}
TruckFahrerGeoData truckFahrerGeoData = new TruckFahrerGeoData();
TruckFahrerGeoPosition truckFahrerGeoPosition = new TruckFahrerGeoPosition();
try
{
Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: BEFORE GPS Fetch.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: BEFORE GPS Fetch.");
var crossGeolocator = CrossGeolocator.Current;
if (crossGeolocator == null)
{
Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: crossGeolocator == null.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: crossGeolocator == null.");
return;
}
// getting GPS status
var gpsSensorStatus = await GeoLocationDataManager.Instance.HasGpsPermissionsEnabled(serviceMode: IsRunningAsService);
if (!gpsSensorStatus)
{
var notificationManager = (NotificationManager) GetSystemService(NotificationService);
if (notificationManager != null)
{
try
{
Intent gpsSettingsIntent = new Intent(Settings.ActionLocationSourceSettings);
//activity will not be launched if it is already running at the top of the history stack.
gpsSettingsIntent.AddFlags(ActivityFlags.SingleTop);
if (IsRunningAsService)
{
gpsSettingsIntent.AddFlags(ActivityFlags.NewTask);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
var notification = builder
.SetContentIntent(PendingIntent.GetActivity(this, 0, gpsSettingsIntent, 0))
.SetSmallIcon(Resource.Drawable.ic_launcher)
.SetContentTitle("Nachricht von TruckerApp GPS Service")
.SetTicker("Nachricht von TruckerApp GPS Service")
.SetContentText("GPS basierte Auftragszuteilung konnte nicht gestarted werden. " +
"Bitte aktivieren Sie GPS in den Einstellungen. " +
"Diese ist nur innerhalb möglicher Transportzeiten von Mo-Fr von 04:00:00-21:00:00 Uhr erforderlich. " +
"Ausserhalb dieser Zeiten werden keine GPS Daten verwendet.")
.SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
.SetAutoCancel(true)
.Build();
notificationManager.Notify(GPS_NOT_ENABLED_NOTIFICATION_ID, notification);
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.HandleTimerCallback :: (at Notification) Exception:{e.Message} Type:{e.GetType().Name}");
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
}
else
{
Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: notificationManager == null.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: notificationManager == null.");
}
return;
}
crossGeolocator.DesiredAccuracy = 50;
var location = await crossGeolocator.GetPositionAsync(TimeSpan.FromSeconds(5));
if (location == null)
{
Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: location == null from LocationManager.GpsProvider");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: location == null from LocationManager.GpsProvider.");
return;
}
int castedLat = (int) location.Latitude;
int castedLon = (int) location.Longitude;
if (castedLat == 0 || castedLon == 0)
{
Log.Debug(LogTag, $"GpsTrackerService.HandleTimerCallback ::Skip that Lat/Lon({castedLat}/{castedLon}) because of 0 values.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, $"GpsTrackerService.HandleTimerCallback ::Skip that Lat/Lon({castedLat}/{castedLon}) because of 0 values.");
return;
}
truckFahrerGeoPosition.Latitude = location.Latitude;
truckFahrerGeoPosition.Longitude = location.Longitude;
truckFahrerGeoPosition.Accuracy = location.Accuracy;
truckFahrerGeoPosition.Speed = location.Speed;
await GpsTrackerServiceUtils.PersistGeoLocationData(LogTag, _mobileServiceClient, this, truckFahrerGeoPosition, truckFahrerGeoData);
Log.Debug(LogTag, "GpsTrackerService.HandleTimerCallback :: AFTER GPS Fetch.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.HandleTimerCallback :: AFTER GPS Fetch.");
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.HandleTimerCallback :: Exception:{e.Message} Type:{e.GetType().Name}, Stacktrack:{e.StackTrace}");
if (e.InnerException != null)
{
Log.Debug(LogTag, $"GpsTrackerService.HandleTimerCallback :: Exception:{e.InnerException.Message} Type:{e.InnerException.GetType().Name}, Stacktrack:{e.InnerException.StackTrace}");
}
Dictionary<string, string> telemetryDictionary = new Dictionary<string, string>();
var serializedGeoData = JsonConvert.SerializeObject(truckFahrerGeoData);
telemetryDictionary.Add("TruckFahrerGeoData", serializedGeoData);
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Error", LogTag, _mobileServiceClient, this, e.Message, telemetryDictionary);
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
}
}
public override IBinder OnBind(Intent intent)
{
// This is a started service, not a bound service, so we just return null.
return null;
}
public override void OnDestroy()
{
try
{
Log.Debug(LogTag, "GpsTrackerService.OnDestroy :: Service stopped.");
GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnStartCommand :: Service stopped.");
StopForeground(removeNotification: true);
// Remove the notification from the status bar.
var notificationManager = (NotificationManager) GetSystemService(NotificationService);
notificationManager.Cancel(SERVICE_RUNNING_NOTIFICATION_ID);
// whe app is running and service stopped on task manager
if (MainActivity.CurrentActivity != null)
{
Intent broadcastIntent = new Intent(action: GpsConstants.GpsRestart);
SendBroadcast(broadcastIntent);
}
//TODO: We must discuss that in detail. Currently no restart occurs on service. If desired uncomment the below lines.
// TODO: Maybe through a flag in TruckFahrer Table. e.g. if tf.Status == "FULLTIME_ROLSPED" -> restart service on app close .
//Intent broadcastIntent = new Intent(action: GpsConstants.GpsRestart);
//SendBroadcast(broadcastIntent);
//Log.Debug(LogTag, "GpsTrackerService.OnDestroy :: Gps Service restart broadcast message sent.");
//GpsTrackerServiceUtils.SendGenericMessageToApplicationInsights("Gps-Info", LogTag, _mobileServiceClient, this, "GpsTrackerService.OnDestroy :: Gps Service restart broadcast message sent.");
}
catch (Exception e)
{
Log.Debug(LogTag, $"GpsTrackerService.OnDestroy :: Exception:{e.Message} Type:{e.GetType().Name}");
GpsTrackerServiceUtils.SendExceptionToApplicationInsights(e, LogTag, _mobileServiceClient, this);
}
base.OnDestroy();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment