diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index 8ecb1814a..e73f1d411 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -106,7 +106,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.entities.Device; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService; import nodomain.freeyourgadget.gadgetbridge.externalevents.opentracks.OpenTracksContentObserver; import nodomain.freeyourgadget.gadgetbridge.externalevents.opentracks.OpenTracksController; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; @@ -659,7 +659,7 @@ public class DebugActivity extends AbstractGBActivity { stopPhoneGpsLocationListener.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - GBLocationManager.stopAll(getBaseContext()); + GBLocationService.stop(DebugActivity.this, null); } }); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationListener.java index a207e1027..59c51b459 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationListener.java @@ -21,10 +21,14 @@ import android.location.LocationListener; import android.os.Bundle; import android.os.SystemClock; +import androidx.annotation.NonNull; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; /** * An implementation of a {@link LocationListener} that forwards the location updates to the @@ -33,18 +37,18 @@ import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; public class GBLocationListener implements LocationListener { private static final Logger LOG = LoggerFactory.getLogger(GBLocationListener.class); - private final EventHandler eventHandler; + private final GBDevice device; private Location previousLocation; // divide by 3.6 to get km/h to m/s private static final double SPEED_THRESHOLD = 1.0 / 3.6; - public GBLocationListener(final EventHandler eventHandler) { - this.eventHandler = eventHandler; + public GBLocationListener(final GBDevice device) { + this.device = device; } @Override - public void onLocationChanged(final Location location) { + public void onLocationChanged(@NonNull final Location location) { LOG.info("Location changed: {}", location); // Correct the location time @@ -61,16 +65,16 @@ public class GBLocationListener implements LocationListener { previousLocation = location; - eventHandler.onSetGpsLocation(location); + GBApplication.deviceService(device).onSetGpsLocation(location); } @Override - public void onProviderDisabled(final String provider) { + public void onProviderDisabled(@NonNull final String provider) { LOG.info("onProviderDisabled: {}", provider); } @Override - public void onProviderEnabled(final String provider) { + public void onProviderEnabled(@NonNull final String provider) { LOG.info("onProviderDisabled: {}", provider); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationManager.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationManager.java deleted file mode 100644 index 2002d6ec8..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationManager.java +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright (C) 2022-2024 halemmerich, José Rebelo, LukasEdl, Martin Boonk - - This file is part of Gadgetbridge. - - Gadgetbridge is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Gadgetbridge is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; - -import android.content.Context; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.os.Bundle; -import android.os.Looper; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; -import nodomain.freeyourgadget.gadgetbridge.util.GB; - - -/** - * A static location manager, which keeps track of what providers are currently running. A notification is kept - * while there is at least one provider running. - */ -public class GBLocationManager { - private static final Logger LOG = LoggerFactory.getLogger(GBLocationManager.class); - - /** - * The current number of running listeners. - */ - private static Map> providers = new HashMap<>(); - - public static void start(final Context context, final EventHandler eventHandler) { - GBLocationManager.start(context, eventHandler, LocationProviderType.GPS, null); - } - - public static void start(final Context context, final EventHandler eventHandler, final LocationProviderType providerType, Integer updateInterval) { - LOG.info("Starting"); - if (providers.containsKey(eventHandler) && providers.get(eventHandler).containsKey(providerType)) { - LOG.warn("EventHandler already registered"); - return; - } - - GB.createGpsNotification(context, providers.size()); - - final GBLocationListener locationListener = new GBLocationListener(eventHandler); - final AbstractLocationProvider locationProvider; - switch (providerType) { - case GPS: - LOG.info("Using gps location provider"); - locationProvider = new PhoneGpsLocationProvider(locationListener); - break; - case NETWORK: - LOG.info("Using network location provider"); - locationProvider = new PhoneNetworkLocationProvider(locationListener); - break; - default: - LOG.info("Using default location provider: GPS"); - locationProvider = new PhoneGpsLocationProvider(locationListener); - } - - if (updateInterval != null) { - locationProvider.start(context, updateInterval); - } else { - locationProvider.start(context); - } - - if (providers.containsKey(eventHandler)) { - providers.get(eventHandler).put(providerType, locationProvider); - } else { - Map providerMap = new HashMap<>(); - providerMap.put(providerType, locationProvider); - providers.put(eventHandler, providerMap); - } - } - - public static void stop(final Context context, final EventHandler eventHandler) { - GBLocationManager.stop(context, eventHandler, null); - } - - public static void stop(final Context context, final EventHandler eventHandler, final LocationProviderType gpsType) { - if (!providers.containsKey(eventHandler)) return; - Map providerMap = providers.get(eventHandler); - if (gpsType == null) { - Set toBeRemoved = new HashSet<>(); - for (LocationProviderType providerType: providerMap.keySet()) { - stopProvider(context, providerMap.get(providerType)); - toBeRemoved.add(providerType); - } - for (final LocationProviderType providerType : toBeRemoved) { - providerMap.remove(providerType); - } - } else { - stopProvider(context, providerMap.get(gpsType)); - providerMap.remove(gpsType); - } - LOG.debug("Remaining providers: " + providers.size()); - if (providers.get(eventHandler).size() == 0) - providers.remove(eventHandler); - updateNotification(context); - } - - private static void updateNotification(final Context context){ - if (!providers.isEmpty()) { - GB.createGpsNotification(context, providers.size()); - } else { - GB.removeGpsNotification(context); - } - } - - private static void stopProvider(final Context context, AbstractLocationProvider locationProvider) { - if (locationProvider != null) { - locationProvider.stop(context); - } - } - - public static void stopAll(final Context context) { - for (EventHandler eventHandler : providers.keySet()) { - stop(context, eventHandler); - } - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/AbstractLocationProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationProvider.java similarity index 70% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/AbstractLocationProvider.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationProvider.java index 6789512d6..efb8f7728 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/AbstractLocationProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationProvider.java @@ -22,35 +22,30 @@ import android.location.LocationListener; /** * An abstract location provider, which periodically sends a location update to the provided {@link LocationListener}. */ -public abstract class AbstractLocationProvider { +public abstract class GBLocationProvider { + private final Context context; private final LocationListener locationListener; - public AbstractLocationProvider(final LocationListener locationListener) { + public GBLocationProvider(final Context context, final LocationListener locationListener) { + this.context = context; this.locationListener = locationListener; } - protected final LocationListener getLocationListener() { + public final Context getContext() { + return this.context; + } + + public final LocationListener getLocationListener() { return this.locationListener; } /** * Start sending periodic location updates. - * - * @param context the {@link Context}. */ - abstract void start(final Context context); - - /** - * Start sending periodic location updates. - * - * @param context the {@link Context}. - */ - abstract void start(final Context context, final int interval); + public abstract void start(final int interval); /** * Stop sending periodic location updates. - * - * @param context the {@link Context}. */ - abstract void stop(final Context context); + public abstract void stop(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationProviderType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationProviderType.java new file mode 100644 index 000000000..0834fb348 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationProviderType.java @@ -0,0 +1,47 @@ +/* Copyright (C) 2022-2024 LukasEdl + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; + +import android.content.Context; +import android.location.LocationManager; + +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.providers.MockLocationProvider; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.providers.PhoneLocationProvider; + +public enum GBLocationProviderType { + GPS { + @Override + public GBLocationProvider newInstance(final Context context, final GBLocationListener locationListener) { + return new PhoneLocationProvider(context, locationListener, LocationManager.GPS_PROVIDER); + } + }, + NETWORK { + @Override + public GBLocationProvider newInstance(final Context context, final GBLocationListener locationListener) { + return new PhoneLocationProvider(context, locationListener, LocationManager.NETWORK_PROVIDER); + } + }, + MOCK { + @Override + public GBLocationProvider newInstance(final Context context, final GBLocationListener locationListener) { + return new MockLocationProvider(context, locationListener); + } + }, + ; + + public abstract GBLocationProvider newInstance(final Context context, final GBLocationListener locationListener); +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationService.java new file mode 100644 index 000000000..0f41076f1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/GBLocationService.java @@ -0,0 +1,188 @@ +/* Copyright (C) 2022-2024 halemmerich, José Rebelo, LukasEdl, Martin Boonk + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.util.GB; +import nodomain.freeyourgadget.gadgetbridge.util.PendingIntentUtils; + + +/** + * A static location manager, which keeps track of what providers are currently running. A notification is kept + * while there is at least one provider running. + */ +public class GBLocationService extends BroadcastReceiver { + private static final Logger LOG = LoggerFactory.getLogger(GBLocationService.class); + + public static final String ACTION_START = "GBLocationService.START"; + public static final String ACTION_STOP = "GBLocationService.STOP"; + public static final String ACTION_STOP_ALL = "GBLocationService.STOP_ALL"; + + public static final String EXTRA_TYPE = "extra_type"; + public static final String EXTRA_INTERVAL = "extra_interval"; + + private final Context context; + private final Map> providersByDevice = new HashMap<>(); + + public GBLocationService(final Context context) { + this.context = context; + } + + @Override + public void onReceive(final Context context, final Intent intent) { + if (intent.getAction() == null) { + LOG.warn("Action is null"); + return; + } + + final GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE); + + switch (intent.getAction()) { + case ACTION_START: + if (device == null) { + LOG.error("Device is null for {}", intent.getAction()); + return; + } + + final GBLocationProviderType providerType = GBLocationProviderType.valueOf( + intent.hasExtra(EXTRA_TYPE) ? intent.getStringExtra(EXTRA_TYPE) : "GPS" + ); + final int updateInterval = intent.getIntExtra(EXTRA_INTERVAL, 1000); + + LOG.debug("Starting location provider {} for {}", providerType, device.getAliasOrName()); + + if (!providersByDevice.containsKey(device)) { + providersByDevice.put(device, new ArrayList<>()); + } + + updateNotification(); + + final List existingProviders = providersByDevice.get(device); + + final GBLocationListener locationListener = new GBLocationListener(device); + final GBLocationProvider locationProvider = providerType.newInstance(context, locationListener); + locationProvider.start(updateInterval); + Objects.requireNonNull(existingProviders).add(locationProvider); + return; + case ACTION_STOP: + if (device == null) { + LOG.error("Device is null for {}", intent.getAction()); + return; + } + stopDevice(device); + updateNotification(); + return; + case ACTION_STOP_ALL: + stopAll(); + return; + default: + LOG.warn("Unknown action {}", intent.getAction()); + } + } + + public void stopDevice(final GBDevice device) { + LOG.debug("Stopping location providers for {}", device.getAliasOrName()); + + final List providers = providersByDevice.remove(device); + if (providers != null) { + for (final GBLocationProvider provider : providers) { + provider.stop(); + } + } + } + + public IntentFilter buildFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_START); + intentFilter.addAction(ACTION_STOP); + return intentFilter; + } + + public void stopAll() { + final List gbDevices = new ArrayList<>(providersByDevice.keySet()); + for (GBDevice d : gbDevices) { + stopDevice(d); + } + + updateNotification(); + } + + public static void start(final Context context, + @NonNull final GBDevice device, + final GBLocationProviderType providerType, + final int updateInterval) { + final Intent intent = new Intent(ACTION_START); + intent.putExtra(GBDevice.EXTRA_DEVICE, device); + intent.putExtra(EXTRA_TYPE, providerType.name()); + intent.putExtra(EXTRA_INTERVAL, updateInterval); + LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + } + + public static void stop(final Context context, @Nullable final GBDevice device) { + final Intent intent = new Intent(ACTION_STOP); + intent.putExtra(GBDevice.EXTRA_DEVICE, device); + LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + } + + private void updateNotification() { + if (!providersByDevice.isEmpty()) { + final Intent notificationIntent = new Intent(context, ControlCenterv2.class); + notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + final PendingIntent pendingIntent = PendingIntentUtils.getActivity(context, 0, notificationIntent, 0, false); + + final NotificationCompat.Builder nb = new NotificationCompat.Builder(context, GB.NOTIFICATION_CHANNEL_ID_GPS) + .setTicker(context.getString(R.string.notification_gps_title)) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setContentTitle(context.getString(R.string.notification_gps_title)) + .setContentText(context.getString(R.string.notification_gps_text, providersByDevice.size())) + .setContentIntent(pendingIntent) + .setSmallIcon(R.drawable.ic_gps_location) + .setOngoing(true); + + final Intent stopAllIntent = new Intent(context, GBLocationService.class); + stopAllIntent.setAction(ACTION_STOP); + final PendingIntent stopAllPendingIntent = PendingIntentUtils.getService(context, 1, stopAllIntent, PendingIntent.FLAG_ONE_SHOT, false); + nb.addAction(R.drawable.ic_stop, context.getString(R.string.stop), stopAllPendingIntent); + + GB.notify(GB.NOTIFICATION_ID_GPS, nb.build(), context); + } else { + GB.removeNotification(GB.NOTIFICATION_ID_GPS, context); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/LocationProviderType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/LocationProviderType.java deleted file mode 100644 index c040abec1..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/LocationProviderType.java +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (C) 2022-2024 LukasEdl - - This file is part of Gadgetbridge. - - Gadgetbridge is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Gadgetbridge is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; - -public enum LocationProviderType { - GPS, - NETWORK, -} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/PhoneNetworkLocationProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/PhoneNetworkLocationProvider.java deleted file mode 100644 index 7d0a1a624..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/PhoneNetworkLocationProvider.java +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2022-2024 Lukas, LukasEdl - - This file is part of Gadgetbridge. - - Gadgetbridge is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Gadgetbridge is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; - -import android.Manifest; -import android.content.Context; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.os.Looper; -import android.widget.Toast; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import nodomain.freeyourgadget.gadgetbridge.util.GB; - -/** - * A location provider that uses the phone GPS, using {@link LocationManager}. - */ -public class PhoneNetworkLocationProvider extends AbstractLocationProvider { - private static final Logger LOG = LoggerFactory.getLogger(PhoneNetworkLocationProvider.class); - - private static final int INTERVAL_MIN_TIME = 1000; - private static final int INTERVAL_MIN_DISTANCE = 0; - - public PhoneNetworkLocationProvider(LocationListener locationListener) { - super(locationListener); - } - - @Override - void start(final Context context) { - start(context, INTERVAL_MIN_TIME); - } - - @Override - void start(Context context, int interval) { - LOG.info("Starting phone network location provider"); - - if (!GB.checkPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) && !GB.checkPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) { - GB.toast("Location permission not granted", Toast.LENGTH_SHORT, GB.ERROR); - return; - } - - final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - locationManager.removeUpdates(getLocationListener()); - locationManager.requestLocationUpdates( - LocationManager.NETWORK_PROVIDER, - interval, - INTERVAL_MIN_DISTANCE, - getLocationListener(), - Looper.getMainLooper() - ); - - final Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); - LOG.debug("Last known network location: {}", lastKnownLocation); - } - - @Override - void stop(final Context context) { - LOG.info("Stopping phone network location provider"); - - final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - locationManager.removeUpdates(getLocationListener()); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/MockLocationProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/providers/MockLocationProvider.java similarity index 59% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/MockLocationProvider.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/providers/MockLocationProvider.java index 66ab2f2c9..06cce4171 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/MockLocationProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/providers/MockLocationProvider.java @@ -14,7 +14,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; +package nodomain.freeyourgadget.gadgetbridge.externalevents.gps.providers; import android.content.Context; import android.location.Location; @@ -26,13 +26,14 @@ import android.os.SystemClock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProvider; import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.CurrentPosition; /** * A mock location provider which keeps updating the location at a constant speed, starting from the * last known location. Useful for local tests. */ -public class MockLocationProvider extends AbstractLocationProvider { +public class MockLocationProvider extends GBLocationProvider { private static final Logger LOG = LoggerFactory.getLogger(MockLocationProvider.class); private Location previousLocation = new CurrentPosition().getLastKnownLocation(); @@ -40,12 +41,12 @@ public class MockLocationProvider extends AbstractLocationProvider { /** * Interval between location updates, in milliseconds. */ - private final int interval = 1000; + private static final int DEFAULT_INTERVAL = 1000; /** * Difference between location updates, in degrees. */ - private final float coordDiff = 0.0002f; + private static final float COORD_DIFF = 0.0002f; /** * Whether the handler is running. @@ -54,50 +55,40 @@ public class MockLocationProvider extends AbstractLocationProvider { private final Handler handler = new Handler(Looper.getMainLooper()); - private final Runnable locationUpdateRunnable = new Runnable() { - @Override - public void run() { - if (!running) { - return; - } - - final Location newLocation = new Location(previousLocation); - newLocation.setLatitude(previousLocation.getLatitude() + coordDiff); - newLocation.setTime(System.currentTimeMillis()); - newLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); - - getLocationListener().onLocationChanged(newLocation); - - previousLocation = newLocation; - - if (running) { - handler.postDelayed(this, interval); - } - } - }; - - public MockLocationProvider(LocationListener locationListener) { - super(locationListener); + public MockLocationProvider(final Context context, final LocationListener locationListener) { + super(context, locationListener); } @Override - void start(final Context context) { + public void start(final int interval) { LOG.info("Starting mock location provider"); running = true; - handler.postDelayed(locationUpdateRunnable, interval); + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (!running) { + return; + } + + final Location newLocation = new Location(previousLocation); + newLocation.setLatitude(previousLocation.getLatitude() + COORD_DIFF); + newLocation.setTime(System.currentTimeMillis()); + newLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + + getLocationListener().onLocationChanged(newLocation); + + previousLocation = newLocation; + + if (running) { + handler.postDelayed(this, interval); + } + } + }, interval > 0 ? interval : DEFAULT_INTERVAL); } @Override - void start(final Context context, int minInterval) { - LOG.info("Starting mock location provider"); - - running = true; - handler.postDelayed(locationUpdateRunnable, interval); - } - - @Override - void stop(final Context context) { + public void stop() { LOG.info("Stopping mock location provider"); running = false; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/PhoneGpsLocationProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/providers/PhoneLocationProvider.java similarity index 69% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/PhoneGpsLocationProvider.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/providers/PhoneLocationProvider.java index bb926e0f7..7049b7c3d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/PhoneGpsLocationProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/gps/providers/PhoneLocationProvider.java @@ -14,7 +14,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.externalevents.gps; +package nodomain.freeyourgadget.gadgetbridge.externalevents.gps.providers; import android.Manifest; import android.content.Context; @@ -27,43 +27,38 @@ import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProvider; import nodomain.freeyourgadget.gadgetbridge.util.GB; /** * A location provider that uses the phone GPS, using {@link LocationManager}. */ -public class PhoneGpsLocationProvider extends AbstractLocationProvider { - private static final Logger LOG = LoggerFactory.getLogger(PhoneGpsLocationProvider.class); +public class PhoneLocationProvider extends GBLocationProvider { + private static final Logger LOG = LoggerFactory.getLogger(PhoneLocationProvider.class); + + private final String provider; - private static final int INTERVAL_MIN_TIME = 1000; private static final int INTERVAL_MIN_DISTANCE = 0; - public PhoneGpsLocationProvider(LocationListener locationListener) { - super(locationListener); - } - public PhoneGpsLocationProvider(LocationListener locationListener, int intervalTime) { - super(locationListener); + public PhoneLocationProvider(final Context context, final LocationListener locationListener, final String provider) { + super(context, locationListener); + this.provider = provider; } @Override - void start(final Context context) { - start(context, INTERVAL_MIN_TIME); - } - - @Override - void start(Context context, int interval) { + public void start(final int interval) { LOG.info("Starting phone gps location provider"); - if (!GB.checkPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) && !GB.checkPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) { + if (!GB.checkPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) && !GB.checkPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION)) { GB.toast("Location permission not granted", Toast.LENGTH_SHORT, GB.ERROR); return; } - final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + final LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); locationManager.removeUpdates(getLocationListener()); locationManager.requestLocationUpdates( - LocationManager.GPS_PROVIDER, - interval, + provider, + interval > 0 ? interval : 1_000, INTERVAL_MIN_DISTANCE, getLocationListener(), Looper.getMainLooper() @@ -74,10 +69,10 @@ public class PhoneGpsLocationProvider extends AbstractLocationProvider { } @Override - void stop(final Context context) { + public void stop() { LOG.info("Stopping phone gps location provider"); - final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + final LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE); locationManager.removeUpdates(getLocationListener()); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index a2f9117b5..fa5816275 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -82,7 +82,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.SMSReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.SilentModeReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.TinyWeatherForecastGermanyReceiver; -import nodomain.freeyourgadget.gadgetbridge.externalevents.sleepasandroid.SleepAsAndroidAction; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService; import nodomain.freeyourgadget.gadgetbridge.externalevents.sleepasandroid.SleepAsAndroidReceiver; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService; @@ -140,7 +140,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere } } - private class FeatureSet{ + private static class FeatureSet { private boolean supportsWeather = false; private boolean supportsActivityDataFetching = false; private boolean supportsCalendarEvents = false; @@ -256,7 +256,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private AutoConnectIntervalReceiver mAutoConnectInvervalReceiver = null; private AlarmReceiver mAlarmReceiver = null; - private List mCalendarReceiver = new ArrayList<>(); + private final List mCalendarReceiver = new ArrayList<>(); private CMWeatherReceiver mCMWeatherReceiver = null; private LineageOsWeatherReceiver mLineageOsWeatherReceiver = null; private TinyWeatherForecastGermanyReceiver mTinyWeatherForecastGermanyReceiver = null; @@ -264,6 +264,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private OmniJawsObserver mOmniJawsObserver = null; private final DeviceSettingsReceiver deviceSettingsReceiver = new DeviceSettingsReceiver(); private final IntentApiReceiver intentApiReceiver = new IntentApiReceiver(); + private GBLocationService locationService = null; private OsmandEventReceiver mOsmandAidlHelper = null; @@ -1342,6 +1343,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere registerReceiver(mSilentModeReceiver, filter); } + if (locationService == null) { + locationService = new GBLocationService(this); + registerReceiver(locationService, locationService.buildFilter()); + } + if (mOsmandAidlHelper == null && features.supportsNavigation()) { mOsmandAidlHelper = new OsmandEventReceiver(this.getApplication()); } @@ -1424,6 +1430,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mSilentModeReceiver); mSilentModeReceiver = null; } + if (locationService != null) { + unregisterReceiver(locationService); + locationService.stopAll(); + locationService = null; + } if (mCMWeatherReceiver != null) { unregisterReceiver(mCMWeatherReceiver); mCMWeatherReceiver = null; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java index 85175ea69..476cc690d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java @@ -120,8 +120,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncState; import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.LocationProviderType; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; @@ -215,7 +215,7 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport { if (!gpsUpdateSetup) return; LOG.info("Stop location updates"); - GBLocationManager.stop(getContext(), this); + GBLocationService.stop(getContext(), getDevice()); gpsUpdateSetup = false; } @@ -1140,14 +1140,14 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport { LOG.info("Using combined GPS and NETWORK based location: " + onlyUseNetworkGPS); if (!onlyUseNetworkGPS) { try { - GBLocationManager.start(getContext(), this, LocationProviderType.GPS, intervalLength); + GBLocationService.start(getContext(), getDevice(), GBLocationProviderType.GPS, intervalLength); } catch (IllegalArgumentException e) { LOG.warn("GPS provider could not be started", e); } } try { - GBLocationManager.start(getContext(), this, LocationProviderType.NETWORK, intervalLength); + GBLocationService.start(getContext(), getDevice(), GBLocationProviderType.NETWORK, intervalLength); } catch (IllegalArgumentException e) { LOG.warn("NETWORK provider could not be started", e); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java index 80ce3d4c6..b33786ab4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/HuamiSupport.java @@ -30,7 +30,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.location.Location; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.widget.Toast; @@ -117,7 +116,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample; import nodomain.freeyourgadget.gadgetbridge.entities.User; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService; import nodomain.freeyourgadget.gadgetbridge.externalevents.opentracks.OpenTracksController; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; @@ -2010,7 +2010,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements if (sendGpsToBand) { lastPhoneGpsSent = 0; sendPhoneGps(HuamiPhoneGpsStatus.SEARCHING, null); - GBLocationManager.start(getContext(), this); + GBLocationService.start(getContext(), getDevice(), GBLocationProviderType.GPS, 1000); } else { sendPhoneGps(HuamiPhoneGpsStatus.DISABLED, null); } @@ -2030,7 +2030,7 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport implements protected void onWorkoutEnd() { final boolean startOnPhone = HuamiCoordinator.getWorkoutStartOnPhone(getDevice().getAddress()); - GBLocationManager.stop(getContext(), this); + GBLocationService.stop(getContext(), getDevice()); if (startOnPhone) { LOG.info("Stopping OpenTracks recording"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java index 00ccf6981..490eb2152 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java @@ -49,8 +49,6 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationListener; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPhoneInfoRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendMenstrualModifyTimeRequest; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 4c0a7eb33..2421bed8a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -44,7 +44,6 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; -import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinatorSupplier; @@ -65,7 +64,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample; import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample; import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.entities.Alarm; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -228,11 +228,6 @@ public class HuaweiSupportProvider { } public void setGps(boolean start) { - EventHandler handler; - if (isBLE()) - handler = leSupport; - else - handler = brSupport; if (start) { if (!GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()).getBoolean(DeviceSettingsPreferenceConst.PREF_WORKOUT_SEND_GPS_TO_BAND, false)) return; @@ -241,7 +236,7 @@ public class HuaweiSupportProvider { gpsParameterRequest.setFinalizeReq(new RequestCallback() { @Override public void call() { - GBLocationManager.start(getContext(), handler); + GBLocationService.start(getContext(), getDevice(), GBLocationProviderType.GPS, 1000); } }); try { @@ -251,9 +246,9 @@ public class HuaweiSupportProvider { LOG.error("Failed to get GPS parameters", e); } } else - GBLocationManager.start(getContext(), handler); + GBLocationService.start(getContext(), getDevice(), GBLocationProviderType.GPS, 1000); } else - GBLocationManager.stop(getContext(), handler); + GBLocationService.stop(getContext(), getDevice()); } public void setGpsParametersResponse(GpsAndTime.GpsParameters.Response response) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java index b2bf9bd67..7fc56e897 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiHealthService.java @@ -48,7 +48,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.entities.User; import nodomain.freeyourgadget.gadgetbridge.entities.XiaomiActivitySample; -import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationProviderType; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService; import nodomain.freeyourgadget.gadgetbridge.externalevents.opentracks.OpenTracksController; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; @@ -664,7 +665,7 @@ public class XiaomiHealthService extends AbstractXiaomiService { if (!gpsStarted) { gpsStarted = true; gpsFixAcquired = false; - GBLocationManager.start(getSupport().getContext(), getSupport()); + GBLocationService.start(getSupport().getContext(), getSupport().getDevice(), GBLocationProviderType.GPS, 1000); } gpsTimeoutHandler.removeCallbacksAndMessages(null); @@ -673,7 +674,7 @@ public class XiaomiHealthService extends AbstractXiaomiService { LOG.debug("Timed out waiting for workout"); gpsStarted = false; gpsFixAcquired = false; - GBLocationManager.stop(getSupport().getContext(), getSupport()); + GBLocationService.stop(getSupport().getContext(), getSupport().getDevice()); }, 5000); } @@ -696,7 +697,7 @@ public class XiaomiHealthService extends AbstractXiaomiService { case WORKOUT_FINISHED: gpsStarted = false; gpsFixAcquired = false; - GBLocationManager.stop(getSupport().getContext(), getSupport()); + GBLocationService.stop(getSupport().getContext(), getSupport().getDevice()); if (startOnPhone) { OpenTracksController.stopRecording(getSupport().getContext()); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index a151a64ec..802180277 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -500,27 +500,6 @@ public class GB { } } - public static void createGpsNotification(Context context, int numDevices) { - Intent notificationIntent = new Intent(context, ControlCenterv2.class); - notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - PendingIntent pendingIntent = PendingIntentUtils.getActivity(context, 0, notificationIntent, 0, false); - - NotificationCompat.Builder nb = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_GPS) - .setTicker(context.getString(R.string.notification_gps_title)) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setContentTitle(context.getString(R.string.notification_gps_title)) - .setContentText(context.getString(R.string.notification_gps_text, numDevices)) - .setContentIntent(pendingIntent) - .setSmallIcon(R.drawable.ic_gps_location) - .setOngoing(true); - - notify(NOTIFICATION_ID_GPS, nb.build(), context); - } - - public static void removeGpsNotification(Context context) { - removeNotification(NOTIFICATION_ID_GPS, context); - } - private static Notification createInstallNotification(String text, boolean ongoing, int percentage, Context context) { Intent notificationIntent = new Intent(context, ControlCenterv2.class);