package net.osmand.plus; 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.location.LocationListener; import android.location.LocationManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; import android.util.Log; import android.widget.Toast; import net.osmand.PlatformUtil; import net.osmand.plus.notifications.OsmandNotification; import net.osmand.plus.osmo.OsMoPlugin; public class NavigationService extends Service implements LocationListener { public static class NavigationServiceBinder extends Binder { } // global id don't conflict with others public static int USED_BY_NAVIGATION = 1; public static int USED_BY_GPX = 2; public static int USED_BY_LIVE = 4; public final static String USAGE_INTENT = "SERVICE_USED_BY"; public final static String USAGE_OFF_INTERVAL = "SERVICE_OFF_INTERVAL"; private NavigationServiceBinder binder = new NavigationServiceBinder(); private int serviceOffInterval; private String serviceOffProvider; private int serviceError; private OsmandSettings settings; private Handler handler; private static WakeLock lockStatic; private PendingIntent pendingIntent; protected int usedBy = 0; private OsmAndLocationProvider locationProvider; @Override public IBinder onBind(Intent intent) { return binder; } protected synchronized static PowerManager.WakeLock getLock(Context context) { if (lockStatic == null) { PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE); lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "OsmandServiceLock"); } return lockStatic; } protected Handler getHandler() { return handler; } public int getServiceError() { return serviceError; } public int getServiceOffInterval() { return serviceOffInterval; } public int getUsedBy() { return usedBy; } public String getServiceOffProvider() { return serviceOffProvider; } public boolean isUsed() { return usedBy != 0; } public void addUsageIntent(int usageIntent) { usedBy |= usageIntent; } public void stopIfNeeded(Context ctx, int usageIntent) { if ((usedBy & usageIntent) > 0) { usedBy -= usageIntent; } if (usedBy == 0) { final Intent serviceIntent = new Intent(ctx, NavigationService.class); ctx.stopService(serviceIntent); } else { NotificationHelper helper = ((OsmandApplication) getApplication()).getNotificationHelper(); helper.updateTopNotification(); helper.refreshNotifications(); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { handler = new Handler(); final OsmandApplication app = (OsmandApplication) getApplication(); settings = app.getSettings(); usedBy = intent.getIntExtra(USAGE_INTENT, 0); serviceOffInterval = intent.getIntExtra(USAGE_OFF_INTERVAL, 0); if ((usedBy & USED_BY_NAVIGATION) != 0) { serviceOffInterval = 0; } // use only gps provider serviceOffProvider = LocationManager.GPS_PROVIDER; serviceError = serviceOffInterval / 5; // 1. not more than 12 mins serviceError = Math.min(serviceError, 12 * 60 * 1000); // 2. not less than 30 seconds serviceError = Math.max(serviceError, 30 * 1000); // 3. not more than serviceOffInterval serviceError = Math.min(serviceError, serviceOffInterval); locationProvider = app.getLocationProvider(); app.setNavigationService(this); // requesting if (isContinuous()) { // request location updates LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); try { locationManager.requestLocationUpdates(serviceOffProvider, 0, 0, NavigationService.this); } catch (SecurityException e) { Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show(); Log.d(PlatformUtil.TAG, "Location service permission not granted"); //$NON-NLS-1$ } catch (IllegalArgumentException e) { Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show(); Log.d(PlatformUtil.TAG, "GPS location provider not available"); //$NON-NLS-1$ } } else { AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, OnNavigationServiceAlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT); alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 500, serviceOffInterval, pendingIntent); } // registering icon at top level // Leave icon visible even for navigation for proper display Notification notification = app.getNotificationHelper().buildTopNotification(); if (notification != null) { startForeground(OsmandNotification.TOP_NOTIFICATION_SERVICE_ID, notification); app.getNotificationHelper().refreshNotifications(); } return START_REDELIVER_INTENT; } @Override public void onCreate() { super.onCreate(); // initializing variables } private boolean isContinuous() { return serviceOffInterval == 0; } @Override public void onDestroy() { super.onDestroy(); final OsmandApplication app = (OsmandApplication) getApplication(); app.setNavigationService(null); usedBy = 0; // remove updates LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); try { locationManager.removeUpdates(this); } catch (SecurityException e) { Log.d(PlatformUtil.TAG, "Location service permission not granted"); //$NON-NLS-1$ } if (!isContinuous()) { WakeLock lock = getLock(this); if (lock.isHeld()) { lock.release(); } } if (pendingIntent != null) { // remove alarm AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.cancel(pendingIntent); } // remove notification stopForeground(Boolean.TRUE); app.getNotificationHelper().updateTopNotification(); app.runInUIThread(new Runnable() { @Override public void run() { app.getNotificationHelper().refreshNotifications(); } }, 500); } @Override public void onLocationChanged(Location l) { if (l != null && !settings.MAP_ACTIVITY_ENABLED.get()) { net.osmand.Location location = OsmAndLocationProvider.convertLocation(l, (OsmandApplication) getApplication()); if (!isContinuous()) { // unregister listener and wait next time LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); try { locationManager.removeUpdates(this); } catch (SecurityException e) { Log.d(PlatformUtil.TAG, "Location service permission not granted"); //$NON-NLS-1$ } WakeLock lock = getLock(this); if (lock.isHeld()) { lock.release(); } } locationProvider.setLocationFromService(location, isContinuous()); } } @Override public void onProviderDisabled(String provider) { Toast.makeText(this, getString(R.string.off_router_service_no_gps_available), Toast.LENGTH_LONG).show(); } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onTaskRemoved(Intent rootIntent) { OsmandApplication app = ((OsmandApplication) getApplication()); app.getNotificationHelper().removeNotifications(); if (app.getNavigationService() != null && app.getSettings().DISABLE_RECORDING_ONCE_APP_KILLED.get()) { OsMoPlugin plugin = OsmandPlugin.getEnabledPlugin(OsMoPlugin.class); if (plugin != null) { if (plugin.getTracker().isEnabledTracker()) { plugin.getTracker().disableTracker(); } } NavigationService.this.stopSelf(); } } }