generated from Grigo/AndroidTemplate
Initial commit: AIS Map Android application
This commit is contained in:
@@ -0,0 +1,595 @@
|
||||
package com.grigowashere.aismap.controllers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.grigowashere.aismap.models.Vessel;
|
||||
import com.grigowashere.aismap.models.AISVessel;
|
||||
import com.grigowashere.aismap.maps.MapInterface;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Главный контроллер приложения
|
||||
* Координирует работу всех компонентов
|
||||
* Использует гибридный подход: координаты через Location API, остальное через NMEA
|
||||
*/
|
||||
public class AppController implements
|
||||
NMEAParser.NMEAParserListener,
|
||||
UDPListener.UDPListenerCallback,
|
||||
AndroidNMEAListener.NMEAMessageCallback,
|
||||
GPSLocationListener.LocationCallback,
|
||||
MapInterface.MarkerClickListener {
|
||||
|
||||
private static final String TAG = "AppController";
|
||||
|
||||
private Context context;
|
||||
private NMEAParser nmeaParser;
|
||||
private UDPListener udpListener;
|
||||
private AndroidNMEAListener androidNmeaListener;
|
||||
private GPSLocationListener gpsLocationListener;
|
||||
private MapInterface mapInterface;
|
||||
|
||||
private Vessel ownVessel;
|
||||
private List<AISVessel> aisVessels;
|
||||
private ExecutorService executor;
|
||||
|
||||
private boolean isUDPEnabled;
|
||||
private boolean isAndroidNMEAEnabled;
|
||||
private boolean isGPSLocationEnabled;
|
||||
|
||||
// Callback для обновления UI
|
||||
private UIUpdateCallback uiUpdateCallback;
|
||||
|
||||
public interface UIUpdateCallback {
|
||||
void onVesselPositionUpdated(Vessel vessel);
|
||||
void onGPSQualityUpdated(Vessel vessel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Расширенный интерфейс для дополнительных UI событий
|
||||
*/
|
||||
public interface ExtendedUIUpdateCallback extends UIUpdateCallback {
|
||||
void onShowOwnVesselBottomSheet();
|
||||
void onShowAISVesselInfo(AISVessel vessel);
|
||||
void onUpdateCompass(float azimuth, List<AISVessel> nearbyVessels);
|
||||
}
|
||||
|
||||
public AppController(Context context) {
|
||||
this.context = context;
|
||||
this.ownVessel = new Vessel();
|
||||
this.aisVessels = new ArrayList<>();
|
||||
this.executor = Executors.newCachedThreadPool();
|
||||
|
||||
initializeControllers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Инициализирует все контроллеры
|
||||
*/
|
||||
private void initializeControllers() {
|
||||
// Инициализация парсера NMEA
|
||||
nmeaParser = new NMEAParser();
|
||||
nmeaParser.setListener(this);
|
||||
|
||||
// Инициализация GPS Location Listener (для координат)
|
||||
gpsLocationListener = new GPSLocationListener(context);
|
||||
gpsLocationListener.setCallback(this);
|
||||
|
||||
// Связываем NMEA парсер с GPS Location Listener для гибридного режима
|
||||
nmeaParser.setGPSLocationListener(gpsLocationListener);
|
||||
nmeaParser.setHybridMode(true);
|
||||
|
||||
// Инициализация UDP слушателя (порт 10110 - стандартный для AIS)
|
||||
udpListener = new UDPListener(10110);
|
||||
udpListener.setCallback(this);
|
||||
|
||||
// Инициализация Android NMEA слушателя (для курса, скорости, DOP)
|
||||
androidNmeaListener = new AndroidNMEAListener(context);
|
||||
androidNmeaListener.setCallback(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает интерфейс карты
|
||||
*/
|
||||
public void setMapInterface(MapInterface mapInterface) {
|
||||
Log.i(TAG, "setMapInterface вызван: " + (mapInterface != null ? "mapInterface установлен" : "mapInterface == null"));
|
||||
this.mapInterface = mapInterface;
|
||||
if (mapInterface != null) {
|
||||
Log.i(TAG, "Устанавливаем MarkerClickListener в MapInterface");
|
||||
mapInterface.setMarkerClickListener(this);
|
||||
Log.i(TAG, "MarkerClickListener установлен, теперь можно создавать маркеры");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает callback для обновления UI
|
||||
*/
|
||||
public void setUIUpdateCallback(UIUpdateCallback callback) {
|
||||
this.uiUpdateCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Запускает все слушатели
|
||||
*/
|
||||
public void startAllListeners() {
|
||||
// GPS Location Listener запускается в главном потоке
|
||||
if (isGPSLocationEnabled) {
|
||||
gpsLocationListener.startListening();
|
||||
}
|
||||
|
||||
// Android NMEA слушатель должен запускаться в главном потоке
|
||||
if (isAndroidNMEAEnabled) {
|
||||
androidNmeaListener.startListening();
|
||||
}
|
||||
|
||||
// UDP слушатель запускается в фоновом потоке
|
||||
if (isUDPEnabled) {
|
||||
executor.execute(() -> {
|
||||
udpListener.start();
|
||||
});
|
||||
}
|
||||
|
||||
// Тестируем NMEA парсер (временно)
|
||||
testNMEAParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Тестирует NMEA парсер (временно для отладки)
|
||||
*/
|
||||
private void testNMEAParser() {
|
||||
Log.i(TAG, "Тестируем NMEA парсер...");
|
||||
|
||||
// Тестовые NMEA сообщения
|
||||
String[] testMessages = {
|
||||
"$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47",
|
||||
"$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A",
|
||||
"$GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48",
|
||||
"$GPGSA,A,3,01,02,03,04,05,06,07,08,09,10,11,12,1.2,0.8,1.0*3E"
|
||||
};
|
||||
|
||||
for (String message : testMessages) {
|
||||
Log.i(TAG, "Тестируем сообщение: " + message);
|
||||
nmeaParser.parseNMEA(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Останавливает все слушатели
|
||||
*/
|
||||
public void stopAllListeners() {
|
||||
executor.execute(() -> {
|
||||
udpListener.stop();
|
||||
androidNmeaListener.stopListening();
|
||||
gpsLocationListener.stopListening();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Включает/выключает UDP слушатель
|
||||
*/
|
||||
public void setUDPEnabled(boolean enabled) {
|
||||
this.isUDPEnabled = enabled;
|
||||
if (enabled && !udpListener.isRunning()) {
|
||||
udpListener.start();
|
||||
} else if (!enabled && udpListener.isRunning()) {
|
||||
udpListener.stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Включает/выключает Android NMEA слушатель
|
||||
*/
|
||||
public void setAndroidNMEAEnabled(boolean enabled) {
|
||||
Log.i(TAG, "🔄 setAndroidNMEAEnabled: " + enabled);
|
||||
this.isAndroidNMEAEnabled = enabled;
|
||||
|
||||
// Android NMEA слушатель управляется в главном потоке
|
||||
if (enabled && !androidNmeaListener.isListening()) {
|
||||
Log.i(TAG, "🚀 Запускаем Android NMEA слушатель...");
|
||||
boolean success = androidNmeaListener.startListening();
|
||||
if (success) {
|
||||
Log.i(TAG, "✅ Android NMEA слушатель успешно запущен");
|
||||
} else {
|
||||
Log.e(TAG, "❌ Не удалось запустить Android NMEA слушатель");
|
||||
}
|
||||
} else if (!enabled && androidNmeaListener.isListening()) {
|
||||
Log.i(TAG, "⏹️ Останавливаем Android NMEA слушатель...");
|
||||
androidNmeaListener.stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Включает/выключает GPS Location слушатель
|
||||
*/
|
||||
public void setGPSLocationEnabled(boolean enabled) {
|
||||
Log.i(TAG, "🔄 setGPSLocationEnabled: " + enabled);
|
||||
this.isGPSLocationEnabled = enabled;
|
||||
|
||||
if (enabled && !gpsLocationListener.isListening()) {
|
||||
Log.i(TAG, "🚀 Запускаем GPS Location слушатель...");
|
||||
boolean success = gpsLocationListener.startListening();
|
||||
if (success) {
|
||||
Log.i(TAG, "✅ GPS Location слушатель успешно запущен");
|
||||
} else {
|
||||
Log.e(TAG, "❌ Не удалось запустить GPS Location слушатель");
|
||||
}
|
||||
} else if (!enabled && gpsLocationListener.isListening()) {
|
||||
Log.i(TAG, "⏹️ Останавливаем GPS Location слушатель...");
|
||||
gpsLocationListener.stopListening();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает UDP порт
|
||||
*/
|
||||
public void setUDPPort(int port) {
|
||||
udpListener.setPort(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Отправляет данные по UDP
|
||||
*/
|
||||
public void sendUDPData(String data, String address, int port) {
|
||||
udpListener.sendData(data, address, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, включен ли UDP слушатель
|
||||
*/
|
||||
public boolean isUDPEnabled() {
|
||||
return isUDPEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, включен ли Android NMEA слушатель
|
||||
*/
|
||||
public boolean isAndroidNMEAEnabled() {
|
||||
return isAndroidNMEAEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, включен ли GPS Location слушатель
|
||||
*/
|
||||
public boolean isGPSLocationEnabled() {
|
||||
return isGPSLocationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет данные нашего судна при клике по маркеру
|
||||
*/
|
||||
private void updateOwnVesselData(Vessel vessel) {
|
||||
if (vessel != null) {
|
||||
// Обновляем только те данные, которые могут быть актуальными
|
||||
// Координаты и основная информация уже обновляются через GPS
|
||||
if (vessel.getCourse() > 0) {
|
||||
ownVessel.setCourse(vessel.getCourse());
|
||||
updateCompass(); // Обновляем компас при изменении курса
|
||||
}
|
||||
if (vessel.getSpeed() > 0) {
|
||||
ownVessel.setSpeed(vessel.getSpeed());
|
||||
}
|
||||
if (vessel.getSatellites() > 0) {
|
||||
ownVessel.setSatellites(vessel.getSatellites());
|
||||
}
|
||||
if (vessel.getAltitude() != 0) {
|
||||
ownVessel.setAltitude(vessel.getAltitude());
|
||||
}
|
||||
if (vessel.getPdop() > 0) {
|
||||
ownVessel.setPdop(vessel.getPdop());
|
||||
ownVessel.setHdop(vessel.getHdop());
|
||||
ownVessel.setVdop(vessel.getVdop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация LocationCallback (GPS Location Listener)
|
||||
|
||||
@Override
|
||||
public void onLocationUpdated(Vessel vessel) {
|
||||
Log.i(TAG, "📍 GPS Location обновлен: lat=" + vessel.getLatitude() +
|
||||
", lon=" + vessel.getLongitude() +
|
||||
", accuracy=" + vessel.getAccuracy() + "м");
|
||||
|
||||
// Обновляем координаты нашего судна
|
||||
ownVessel.setLatitude(vessel.getLatitude());
|
||||
ownVessel.setLongitude(vessel.getLongitude());
|
||||
ownVessel.setAccuracy(vessel.getAccuracy());
|
||||
ownVessel.setFixTime(vessel.getFixTime());
|
||||
ownVessel.setFixQuality(vessel.getFixQuality());
|
||||
|
||||
// Обновляем UI через callback
|
||||
if (uiUpdateCallback != null) {
|
||||
uiUpdateCallback.onVesselPositionUpdated(ownVessel);
|
||||
}
|
||||
|
||||
// Обновляем карту в главном потоке
|
||||
if (mapInterface != null) {
|
||||
Log.i(TAG, "Обновляем позицию на карте...");
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try {
|
||||
Log.i(TAG, "Вызываем mapInterface.updateOwnVesselPosition...");
|
||||
mapInterface.updateOwnVesselPosition(ownVessel);
|
||||
Log.i(TAG, "Позиция на карте обновлена");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Ошибка обновления позиции на карте: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGPSStatusChanged(int status) {
|
||||
Log.i(TAG, "GPS статус изменился: " + status);
|
||||
}
|
||||
|
||||
// Реализация NMEAParserListener
|
||||
|
||||
@Override
|
||||
public void onVesselUpdated(Vessel vessel) {
|
||||
// В гибридном режиме обновляем только дополнительные данные
|
||||
if (vessel.getCourse() > 0) {
|
||||
ownVessel.setCourse(vessel.getCourse());
|
||||
updateCompass(); // Обновляем компас при изменении курса
|
||||
}
|
||||
if (vessel.getSpeed() > 0) {
|
||||
ownVessel.setSpeed(vessel.getSpeed());
|
||||
}
|
||||
if (vessel.getSatellites() > 0) {
|
||||
ownVessel.setSatellites(vessel.getSatellites());
|
||||
}
|
||||
if (vessel.getAltitude() != 0) {
|
||||
ownVessel.setAltitude(vessel.getAltitude());
|
||||
}
|
||||
|
||||
Log.i(TAG, "NMEA данные обновлены: course=" + vessel.getCourse() +
|
||||
", speed=" + vessel.getSpeed() +
|
||||
", satellites=" + vessel.getSatellites());
|
||||
|
||||
// Обновляем UI
|
||||
if (uiUpdateCallback != null) {
|
||||
uiUpdateCallback.onVesselPositionUpdated(ownVessel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDOPUpdated(double pdop, double hdop, double vdop) {
|
||||
Log.i(TAG, "📊 DOP обновлен: PDOP=" + pdop + ", HDOP=" + hdop + ", VDOP=" + vdop);
|
||||
|
||||
// Обновляем DOP значения
|
||||
ownVessel.setPdop(pdop);
|
||||
ownVessel.setHdop(hdop);
|
||||
ownVessel.setVdop(vdop);
|
||||
|
||||
// Обновляем UI
|
||||
if (uiUpdateCallback != null) {
|
||||
uiUpdateCallback.onGPSQualityUpdated(ownVessel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAISVesselUpdated(AISVessel vessel) {
|
||||
// Проверяем, есть ли уже такое судно
|
||||
AISVessel existingVessel = findAISVesselByMMSI(vessel.getMmsi());
|
||||
|
||||
if (existingVessel != null) {
|
||||
// Обновляем существующее судно
|
||||
existingVessel.updatePosition(
|
||||
vessel.getLatitude(),
|
||||
vessel.getLongitude(),
|
||||
vessel.getCourse(),
|
||||
vessel.getSpeed()
|
||||
);
|
||||
|
||||
if (mapInterface != null) {
|
||||
// Используем Handler для выполнения в главном потоке
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try {
|
||||
mapInterface.updateAISVesselPosition(existingVessel);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Ошибка обновления позиции AIS судна на карте: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Добавляем новое судно
|
||||
aisVessels.add(vessel);
|
||||
|
||||
if (mapInterface != null) {
|
||||
// Используем Handler для выполнения в главном потоке
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try {
|
||||
mapInterface.addAISVesselMarker(vessel);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Ошибка добавления AIS судна на карту: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем компас с ближайшими судами
|
||||
updateCompass();
|
||||
|
||||
Log.i(TAG, "AIS судно обновлено: " + vessel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParseError(String error) {
|
||||
Log.e(TAG, "Ошибка парсинга NMEA: " + error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет компас с текущим азимутом и ближайшими судами
|
||||
*/
|
||||
private void updateCompass() {
|
||||
if (uiUpdateCallback instanceof ExtendedUIUpdateCallback) {
|
||||
float azimuth = (float) ownVessel.getCourse();
|
||||
List<AISVessel> nearbyVessels = getNearbyVessels();
|
||||
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
((ExtendedUIUpdateCallback) uiUpdateCallback).onUpdateCompass(azimuth, nearbyVessels);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает список ближайших судов (в пределах 10 км)
|
||||
*/
|
||||
private List<AISVessel> getNearbyVessels() {
|
||||
List<AISVessel> nearby = new ArrayList<>();
|
||||
double maxDistance = 10000; // 10 км в метрах
|
||||
|
||||
for (AISVessel vessel : aisVessels) {
|
||||
double distance = com.grigowashere.aismap.utils.GeoUtils.calculateDistance(ownVessel, vessel);
|
||||
if (distance <= maxDistance) {
|
||||
nearby.add(vessel);
|
||||
}
|
||||
}
|
||||
|
||||
return nearby;
|
||||
}
|
||||
|
||||
// Реализация UDPListenerCallback
|
||||
|
||||
@Override
|
||||
public void onDataReceived(String data, String sourceAddress, int sourcePort) {
|
||||
Log.d(TAG, "UDP данные получены от " + sourceAddress + ":" + sourcePort);
|
||||
|
||||
// Парсим полученные данные как NMEA
|
||||
nmeaParser.parseNMEA(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUDPError(String error) {
|
||||
Log.e(TAG, "UDP ошибка: " + error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String error) {
|
||||
Log.e(TAG, "GPS Location ошибка: " + error);
|
||||
}
|
||||
|
||||
// Реализация NMEAMessageCallback
|
||||
|
||||
@Override
|
||||
public void onNMEAMessage(String message, long timestamp) {
|
||||
Log.i(TAG, "📱 Android NMEA сообщение получено в AppController: " + message);
|
||||
|
||||
// Парсим полученные данные как NMEA
|
||||
nmeaParser.parseNMEA(message);
|
||||
}
|
||||
|
||||
// Реализация MarkerClickListener
|
||||
|
||||
@Override
|
||||
public void onOwnVesselClick(Vessel vessel) {
|
||||
Log.i(TAG, "Клик по нашему судну: " + vessel);
|
||||
// Уведомляем UI о необходимости показать BottomSheet
|
||||
if (uiUpdateCallback != null) {
|
||||
Log.i(TAG, "uiUpdateCallback найден, обновляем данные судна");
|
||||
// Обновляем данные судна перед показом
|
||||
updateOwnVesselData(vessel);
|
||||
// Вызываем специальный callback для показа BottomSheet
|
||||
if (uiUpdateCallback instanceof ExtendedUIUpdateCallback) {
|
||||
Log.i(TAG, "Вызываем onShowOwnVesselBottomSheet");
|
||||
((ExtendedUIUpdateCallback) uiUpdateCallback).onShowOwnVesselBottomSheet();
|
||||
} else {
|
||||
Log.w(TAG, "uiUpdateCallback не является ExtendedUIUpdateCallback");
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "uiUpdateCallback == null!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAISVesselClick(AISVessel vessel) {
|
||||
Log.i(TAG, "Клик по AIS судну: " + vessel);
|
||||
// Уведомляем UI о необходимости показать информацию об AIS судне
|
||||
if (uiUpdateCallback != null && uiUpdateCallback instanceof ExtendedUIUpdateCallback) {
|
||||
((ExtendedUIUpdateCallback) uiUpdateCallback).onShowAISVesselInfo(vessel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Находит AIS судно по MMSI
|
||||
*/
|
||||
private AISVessel findAISVesselByMMSI(String mmsi) {
|
||||
for (AISVessel vessel : aisVessels) {
|
||||
if (mmsi.equals(vessel.getMmsi())) {
|
||||
return vessel;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает наше судно
|
||||
*/
|
||||
public Vessel getOwnVessel() {
|
||||
return ownVessel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает список AIS судов
|
||||
*/
|
||||
public List<AISVessel> getAISVessels() {
|
||||
return new ArrayList<>(aisVessels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Очищает все AIS суда
|
||||
*/
|
||||
public void clearAISVessels() {
|
||||
aisVessels.clear();
|
||||
if (mapInterface != null) {
|
||||
// Используем Handler для выполнения в главном потоке
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try {
|
||||
mapInterface.clearAISVesselMarkers();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Ошибка очистки AIS судов на карте: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Центрирует карту на позиции нашего судна
|
||||
*/
|
||||
public void centerOnOwnVessel() {
|
||||
if (mapInterface != null && ownVessel != null) {
|
||||
// Используем Handler для выполнения в главном потоке
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try {
|
||||
mapInterface.centerOnPosition(ownVessel.getLatitude(), ownVessel.getLongitude());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Ошибка центрирования карты: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Освобождает ресурсы
|
||||
*/
|
||||
public void cleanup() {
|
||||
stopAllListeners();
|
||||
|
||||
if (udpListener != null) {
|
||||
udpListener.cleanup();
|
||||
}
|
||||
|
||||
if (androidNmeaListener != null) {
|
||||
androidNmeaListener.cleanup();
|
||||
}
|
||||
|
||||
if (gpsLocationListener != null) {
|
||||
gpsLocationListener.cleanup();
|
||||
}
|
||||
|
||||
if (executor != null && !executor.isShutdown()) {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user