diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 71f709fe..4dddc0e6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,7 +66,9 @@ android:foregroundServiceType="location" /> - + diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/CellInformation.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/CellInformation.java index 4f37073d..1eeacfd7 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/CellInformation.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/CellInformation.java @@ -219,10 +219,10 @@ public Point getPoint(Point point){ public StringBuilder getStringBuilder(){ StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(" Type: ").append(this.getCellType()); - if(this.getPci() != -1) stringBuilder.append(" PCI: ").append(this.getPci()); + stringBuilder.append(" Type: ").append(this.getCellType()).append("\n"); + if(this.getPci() != -1) stringBuilder.append(" PCI: ").append(this.getPci()).append("\n"); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && this.getAlphaLong() != null && !this.getAlphaLong().equals("N/A") && !this.getAlphaLong().isEmpty()){ - stringBuilder.append(" Alpha Long: ").append(this.getAlphaLong()); + stringBuilder.append(" Alpha Long: ").append(this.getAlphaLong()).append("\n"); } return stringBuilder; } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/LTEInformation.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/LTEInformation.java index 373d705a..f3b158cb 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/LTEInformation.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/LTEInformation.java @@ -235,15 +235,22 @@ public Point getPoint(Point point){ @Override public StringBuilder getStringBuilder(){ StringBuilder stringBuilder = super.getStringBuilder(); - stringBuilder.append(" RSRQ: ").append(this.getRsrq()); - stringBuilder.append(" RSRP: ").append(this.getRsrp()); - stringBuilder.append(" RSSI: ").append(this.getRssi()); - stringBuilder.append(" RSSNR: ").append(this.getRssnr()); - stringBuilder.append(" CQI: ").append(this.getCqi()); - stringBuilder.append(" Bandwidth: ").append(this.getBandwidth()); - stringBuilder.append(" EARFCN: ").append(this.getEarfcn()); - stringBuilder.append(" TimingAdvance: ").append(this.getTimingAdvance()); + String max = Integer.MAX_VALUE + ""; + if(!this.getRsrqString().equals(max)) stringBuilder.append(" RSRQ: ").append(this.getRsrq()).append(" dB").append("\n"); + if(!this.getRsrpString().equals(max)) stringBuilder.append(" RSRP: ").append(this.getRsrp()).append(" dBm").append("\n"); + + if(!this.getRssiString().equals(max)) stringBuilder.append(" RSSI: ").append(this.getRssi()).append(" dBm").append("\n"); + + if(!this.getRssnrString().equals(max)) stringBuilder.append(" RSSNR: ").append(this.getRssnr()).append(" dB").append("\n"); + + if(!this.getCqiString().equals(max)) stringBuilder.append(" CQI: ").append(this.getCqi()).append("\n"); + + if(!this.getBandwidthString().equals(max)) stringBuilder.append(" Bandwidth: ").append(this.getBandwidth()).append(" kHz").append("\n"); + + if(!this.getEarfcnString().equals(max)) stringBuilder.append(" EARFCN: ").append(this.getEarfcn()).append("\n"); + + if(!this.getTimingAdvanceString().equals(max)) stringBuilder.append(" TimingAdvance: ").append(this.getTimingAdvance()).append(" ns").append("\n"); return stringBuilder; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java index a888fc79..110706f7 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java @@ -136,6 +136,18 @@ public List getCqis() { return cqis; } + public int getFirstCqi() { + try { + return cqis.get(0); + } catch (IndexOutOfBoundsException e) { + return 0; + } + } + + public String getFirstCqiString(){ + return Integer.toString(this.getFirstCqi()); + } + public void setCqis(List cqis) { this.cqis = cqis; } @@ -279,11 +291,20 @@ public Point getPoint(Point point){ @Override public StringBuilder getStringBuilder(){ - StringBuilder sb = super.getStringBuilder(); - sb.append(" SSRSQ: ").append(this.getSsrsrq()); - sb.append(" SSRSRP: ").append(this.getSsrsrp()); - sb.append(" SSSINR: ").append(this.getSssinr()); - return sb; - } + StringBuilder stringBuilder = super.getStringBuilder(); + String max = Integer.MAX_VALUE + ""; + if(!this.getSsrsrqString().equals(max)) stringBuilder.append(" SSRSRQ: ").append(this.getSsrsrqString()).append(" dB").append("\n"); + if(!this.getSsrsrpString().equals(max)) stringBuilder.append(" SSRSRP: ").append(this.getSsrsrpString()).append(" dBm").append("\n"); + + if(!this.getSssinrString().equals(max)) stringBuilder.append(" SSRSRP: ").append(this.getSssinrString()).append(" dBm").append("\n"); + + if(!this.getFirstCqiString().equals(max)) stringBuilder.append(" CQI: ").append(this.getFirstCqiString()).append("\n"); + + if(!this.getNrarfcnString().equals(max)) stringBuilder.append(" NRARFCN: ").append(this.getNrarfcnString()).append("\n"); + + if(!this.getTimingAdvanceString().equals(max)) stringBuilder.append(" TimingAdvance: ").append(this.getTimingAdvance()).append(" ns").append("\n"); + + return stringBuilder; + } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/GlobalVars.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/GlobalVars.java index 77ea6ba1..23dbf089 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/GlobalVars.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/GlobalVars.java @@ -25,6 +25,7 @@ public class GlobalVars { public static final String SSRSRP = "SSRSRP"; public static final String SSRSRQ = "SSRSRQ"; public static final String SSSINR = "SSSINR"; + public static final String INFLUX_WRITE_STATUS = "influxdb_write_status"; private static GlobalVars instance; ImageView log_status; private DataProvider dp; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbConnection.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbConnection.java index 4a019198..50b9be6f 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbConnection.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbConnection.java @@ -69,23 +69,22 @@ public void open_write_api() { .exponentialBase(4) .build()); writeApi.listenEvents(BackpressureEvent.class, value -> { - Log.d(TAG, "Backpressure: Reason: " + value.getReason()); - value.logEvent(); + Log.d(TAG, "open_write_api: Could not write to InfluxDBv2 due to backpressure"); }); writeApi.listenEvents(WriteSuccessEvent.class, value -> { + //Log.d(TAG, "open_write_api: Write to InfluxDBv2 was successful"); if ( spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false)) { gv.getLog_status().setColorFilter(Color.argb(255, 0, 255, 0)); } }); writeApi.listenEvents(WriteErrorEvent.class, value -> { - value.logEvent(); + Log.d(TAG, "open_write_api: Could not write to InfluxDBv2 due to error"); if ( spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false)) { gv.getLog_status().setColorFilter(Color.argb(255, 255, 0, 0)); } }); - writeApi.listenEvents(WriteRetriableErrorEvent.class, value -> { - value.logEvent(); + Log.d(TAG, "open_write_api: Could not write to InfluxDBv2 due to retriable error"); if ( spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false)) { gv.getLog_status().setColorFilter(Color.argb(255, 255, 0, 0)); } @@ -109,27 +108,20 @@ public void disconnect() { writeApi.close(); writeApi = null; } catch (com.influxdb.exceptions.InfluxException e) { - Log.d(TAG, "disconnect: Error while closing write API"); - Log.d(TAG,e.toString()); - } - try { - Log.d(TAG, "disconnect: Closing influx connection"); - influxDBClient.close(); - influxDBClient = null; - } catch (com.influxdb.exceptions.InfluxException e) { - Log.d(TAG, "disconnect: Error while closing influx connection"); + Log.e(TAG, "disconnect: Error while closing write API"); Log.d(TAG,e.toString()); } } else { Log.d(TAG, "disconnect() was called on not existing instance of the influx client"); } + Log.d(TAG, "disconnect: InfluxDB connection closed"); } /** * Add a point to the message queue */ public boolean writePoint(Point point) { - if (influxDBClient != null && influxDBClient.ping()) { + if (influxDBClient != null && ping()) { try { writeApi.writePoint(point); } catch (com.influxdb.exceptions.InfluxException e) { @@ -153,7 +145,7 @@ public boolean writePoint(Point point) { public boolean writeRecords(List points) throws IOException { new Thread(() -> { try { - if (influxDBClient != null && influxDBClient.ping()) { + if (influxDBClient != null && ping()) { try { writeApi.writeRecords(WritePrecision.MS, points); } catch (com.influxdb.exceptions.InfluxException e) { @@ -180,18 +172,19 @@ public boolean writeRecords(List points) throws IOException { public boolean writePoints(List points) throws IOException { new Thread(() -> { try { - if (influxDBClient != null && influxDBClient.ping()) { + if (influxDBClient != null && ping()) { try { writeApi.writePoints(points); } catch (com.influxdb.exceptions.InfluxException e) { - Log.d(TAG, "writePoint: Error while writing points to influx DB"); + Log.e(TAG, "writePoint: Error while writing points to influx DB"); Log.d(TAG,e.toString()); } } else { - Log.d(TAG, "writePoints: InfluxDB not reachable: " + url); + Log.e(TAG, "writePoints: InfluxDB not reachable: " + url); } } catch (Exception e) { + Log.e(TAG, "writePoints: Error while writing points to influx DB"); Log.d(TAG,e.toString()); } }).start(); @@ -230,11 +223,12 @@ public boolean onboard() { public boolean flush() { new Thread(() -> { try { - if (influxDBClient.ping()) { + if (ping()) { writeApi.flush(); } } catch (Exception e) { - Log.d(TAG,e.toString()); + Log.e(TAG, "flush: Error while flushing write API"); + Log.d(TAG, "flush: \n"+e.toString()); } }).start(); return true; @@ -243,6 +237,9 @@ public boolean flush() { public WriteApi getWriteApi() { return writeApi; } + public String getUrl() { + return this.url; + } public boolean ping() { return influxDBClient.ping(); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbWriteApiStatus.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbWriteApiStatus.java new file mode 100644 index 00000000..0dc1af0a --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/InfluxdbWriteApiStatus.java @@ -0,0 +1,37 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x; + +import androidx.annotation.NonNull; + +public enum InfluxdbWriteApiStatus { + Backpressure, + WriteSuccess, + WriteErrorEvent, + WriteRetriableErrorEvent, + Unknown; + @NonNull + public String toString() { + switch(this) { + case Backpressure: return "Backpressure"; + case WriteSuccess: return "WriteSuccess"; + case WriteErrorEvent: return "WriteErrorEvent"; + case WriteRetriableErrorEvent: return "WriteRetriableErrorEvent"; + case Unknown:; + default: return "Unknown"; + } + } + public static InfluxdbWriteApiStatus fromString(String str) { + str = str.toLowerCase(); + switch(str) { + case "backpressure": return Backpressure; + case "writesuccess": return WriteSuccess; + case "writeerrorevent": return WriteErrorEvent; + case "writeeetriableerrorevent": return WriteRetriableErrorEvent; + case "unknown": return Unknown; + default: return Unknown; + } + } + + public boolean isEquals(InfluxdbWriteApiStatus status) { + return this==status; + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java index bd6dfcab..5de06761 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java @@ -28,8 +28,13 @@ import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; +import com.influxdb.client.WriteApi; import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.write.Point; +import com.influxdb.client.write.events.BackpressureEvent; +import com.influxdb.client.write.events.WriteErrorEvent; +import com.influxdb.client.write.events.WriteRetriableErrorEvent; +import com.influxdb.client.write.events.WriteSuccessEvent; import java.io.File; import java.io.FileNotFoundException; @@ -47,6 +52,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.DataProvider; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.WifiInformation; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbWriteApiStatus; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; @@ -59,8 +65,6 @@ public class LoggingService extends Service { InfluxdbConnection lic; // local influxDB DataProvider dp; SharedPreferencesGrouper spg; - private Handler notificationHandler; - private HandlerThread notificationHandlerThread; private Handler remoteInfluxHandler; private HandlerThread remoteInfluxHandlerThread; private Handler localInfluxHandler; @@ -70,6 +74,9 @@ public class LoggingService extends Service { private List logFilePoints; private FileOutputStream stream; private int interval; + private InfluxdbWriteApiStatus currentInfluxdbWriteApiStatus = InfluxdbWriteApiStatus.Unknown; + private boolean influxConnectionStatus = true; + private String currentInfluxDbWriteApiStatusMessage = ""; GlobalVars gv; // Handle local on-device logging to logfile private final Runnable localFileUpdate = new Runnable() { @@ -94,21 +101,6 @@ public void run() { localFileHandler.postDelayed(this, interval); } }; - // Handle notification bar update - private final Runnable notification_updater = new Runnable() { - @SuppressLint("ObsoleteSdkInt") - @Override - public void run() { - if(dp == null) { - Log.e(TAG, "run: Data provider is null!"); - return; - } - StringBuilder s = dp.getRegisteredCells().get(0).getStringBuilder(); - builder.setContentText(s); - nm.notify(1, builder.build()); - notificationHandler.postDelayed(this, interval); - } - }; // Handle local on-device influxDB private final Runnable localInfluxUpdate = () -> { @@ -138,6 +130,8 @@ public void run() { remoteInfluxHandler.postDelayed(this, interval);*/ }; + + // Handle remote on-server influxdb update private final Runnable RemoteInfluxUpdate = new Runnable() { @Override @@ -159,38 +153,161 @@ public void onCreate() { gv = GlobalVars.getInstance(); } - @SuppressLint("ObsoleteSdkInt") - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand: Start logging service"); - GlobalVars gv = GlobalVars.getInstance(); - // setup class variables - dp = gv.get_dp(); - nm = getSystemService(NotificationManager.class); - spg = SharedPreferencesGrouper.getInstance(this); - interval = Integer.parseInt(spg.getSharedPreference(SPType.logging_sp).getString("logging_interval", "1000")); + private StringBuilder getStringBuilder() { + StringBuilder s = new StringBuilder(); + s.append("Logging to...\n"); + + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_local_file_log", false)) + s.append("File\n"); + + if(ic == null) { + // influx not initialized + //s.append("InfluxDB: not connected\n"); + if(s.toString().equals("Logging to...\n")) { + s.append("No logging targets enabled\n"); + } + return s; + } + s.append("InfluxDB: "); + if(!influxConnectionStatus){ + //influx not reachable + s.append(ic.getUrl()) + .append(" not reachable\n"); + return s; + } else { + //influx reachable, so showing the writeApi Status + s.append(currentInfluxdbWriteApiStatus).append("\n"); + } + + switch (currentInfluxdbWriteApiStatus) { + case Backpressure: + case WriteErrorEvent: + case WriteRetriableErrorEvent: + s.append("\tReason: ").append(currentInfluxDbWriteApiStatusMessage).append("\n"); + break; + case WriteSuccess: + case Unknown: + default: + break; + } + return s; + } + + private void setupNotification() { // create intent for notifications Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); + StringBuilder s = getStringBuilder(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // create notification - builder = new NotificationCompat.Builder(this, "OMNT_notification_channel").setContentTitle(getText(R.string.loggin_notifaction)).setSmallIcon(R.mipmap.ic_launcher_foreground).setColor(Color.WHITE).setContentIntent(pendingIntent) + builder = new NotificationCompat.Builder(this, "OMNT_notification_channel") + .setContentTitle(getText(R.string.loggin_notifaction)) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setColor(Color.WHITE) + .setContentIntent(pendingIntent) // prevent to swipe the notification away .setOngoing(true) + .setOnlyAlertOnce(true) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)) // don't wait 10 seconds to show the notification .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE); } else { // create notification - builder = new NotificationCompat.Builder(this, "OMNT_notification_channel").setContentTitle(getText(R.string.loggin_notifaction)).setSmallIcon(R.mipmap.ic_launcher_foreground).setColor(Color.WHITE).setContentIntent(pendingIntent) + builder = new NotificationCompat.Builder(this, "OMNT_notification_channel") + .setContentTitle(getText(R.string.loggin_notifaction)) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setColor(Color.WHITE) + .setContentIntent(pendingIntent) + .setOnlyAlertOnce(true) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)) // prevent to swipe the notification away .setOngoing(true); } + } + + private void updateNotification(){ + StringBuilder s = getStringBuilder(); + builder.setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)); + nm.notify(1, builder.build()); + } + private void getInfluxDBConnectionStatus() { + if (ic == null) return; + WriteApi writeApi = ic.getWriteApi(); + if (writeApi == null) return; + + // Listen for different WriteApi events + writeApi.listenEvents(BackpressureEvent.class, event -> + handleWriteApiEvent(InfluxdbWriteApiStatus.Backpressure, event.getReason().toString())); + + writeApi.listenEvents(WriteSuccessEvent.class, event -> + handleWriteApiEvent(InfluxdbWriteApiStatus.WriteSuccess, null)); + + writeApi.listenEvents(WriteErrorEvent.class, event -> + handleWriteApiEvent(InfluxdbWriteApiStatus.WriteErrorEvent, event.getThrowable().getMessage())); + + writeApi.listenEvents(WriteRetriableErrorEvent.class, event -> + handleWriteApiEvent(InfluxdbWriteApiStatus.WriteRetriableErrorEvent, event.getThrowable().getMessage())); + } + + private void handleWriteApiEvent(InfluxdbWriteApiStatus status, String message) { + if (!spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false)) return; + + // Check if status has changed + if (currentInfluxdbWriteApiStatus == status && + (message == null || message.equals(currentInfluxDbWriteApiStatusMessage))) return; + + // Update the status and log message + currentInfluxdbWriteApiStatus = status; + if (message != null) currentInfluxDbWriteApiStatusMessage = message; + + Log.d(TAG, String.format("getInfluxDBConnectionStatus: Could not write to InfluxDBv2 due to %s %s", status.toString(), currentInfluxDbWriteApiStatusMessage)); + + updateNotification(); + } + + + @SuppressLint("ObsoleteSdkInt") + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand: Start logging service"); + GlobalVars gv = GlobalVars.getInstance(); + + // setup class variables + dp = gv.get_dp(); + nm = getSystemService(NotificationManager.class); + spg = SharedPreferencesGrouper.getInstance(this); + interval = Integer.parseInt(spg.getSharedPreference(SPType.logging_sp).getString("logging_interval", "1000")); + + + // create preferences listener spg.setListener((prefs, key) -> { + if(Objects.equals(key, "enable_logging")) { + if (prefs.getBoolean(key, false)) { + Log.d(TAG, "onSharedPreferenceChanged: " + prefs.getBoolean(key, false)); + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false)) { + // enable influx when enable_logging is enabled + setupRemoteInfluxDB(); + } + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_local_file_log", false)){ + // enable local file log when enable_logging is enabled + setupLocalFile(); + updateNotification(); + } + + + } else { + updateNotification(); + this.onDestroy(); + } + } else if (Objects.equals(key, "enable_influx")) { if (prefs.getBoolean(key, false)) { if (prefs.getString("influx_URL", "").isEmpty() || prefs.getString("influx_org", "").isEmpty() || prefs.getString("influx_token", "").isEmpty() || prefs.getString("influx_bucket", "").isEmpty()) { @@ -198,22 +315,34 @@ public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(getApplicationContext(), "Please fill all Influx Settings", Toast.LENGTH_LONG).show(); prefs.edit().putBoolean("enable_influx", false).apply(); } else { - setupRemoteInfluxDB(); + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_logging", false)) { + // only enable influx log, when enable_logging is also enabled + setupRemoteInfluxDB(); + updateNotification(); + } + } } else { - stopRemoteInfluxDB(); - } - } else if (Objects.equals(key, "enable_notification_update")) { - if (prefs.getBoolean(key, false)) { - setupNotificationUpdate(); - } else { - stopNotificationUpdate(); + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_logging", false)) { + // only stop influx log, when enable_logging is also enabled + stopRemoteInfluxDB(); + updateNotification(); + } + } } else if (Objects.equals(key, "enable_local_file_log")) { if (prefs.getBoolean(key, false)) { - setupLocalFile(); + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_logging", false)) { + // only enable file log, when enable_logging is also enabled + setupLocalFile(); + updateNotification(); + } } else { - stopLocalFile(); + if(spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_logging", false)) { + // only stop file log, when enable_logging is also enabled + stopLocalFile(); + updateNotification(); + } } } else if (Objects.equals(key, "enable_local_influx_log")) { if (prefs.getBoolean(key, false)) { @@ -226,13 +355,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { } }, SPType.logging_sp); - // Start foreground service and setup logging targets - startForeground(1, builder.build()); - - if (spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_notification_update", false)) { - setupNotificationUpdate(); - } - if (spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false)) { setupRemoteInfluxDB(); } @@ -244,6 +366,12 @@ public int onStartCommand(Intent intent, int flags, int startId) { if (spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_local_influx_log", false)) { setupLocalFile(); } + + setupNotification(); + // Start foreground service and setup logging targets + startForeground(1, builder.build()); + + return START_STICKY; } @@ -262,6 +390,8 @@ public void onDestroy() { stopLocalInfluxDB(); } + //remove notification + nm.cancel(1); // Stop foreground service and remove the notification. stopForeground(STOP_FOREGROUND_DETACH); // Stop the foreground service. @@ -434,30 +564,6 @@ private void stopLocalFile() { } } - private void setupNotificationUpdate() { - Log.d(TAG, "setupNotificationUpdate"); - notificationHandlerThread = new HandlerThread("NotificationHandlerThread"); - notificationHandlerThread.start(); - notificationHandler = new Handler(Objects.requireNonNull(notificationHandlerThread.getLooper())); - notificationHandler.post(notification_updater); - } - - private void stopNotificationUpdate() { - Log.d(TAG, "stopNotificationUpdate"); - notificationHandler.removeCallbacks(notification_updater); - builder.setContentText(null); - nm.notify(1, builder.build()); - - if (notificationHandlerThread != null) { - notificationHandlerThread.quitSafely(); - try { - notificationHandlerThread.join(); - } catch (InterruptedException e) { - Log.e(TAG, "Exception happened!! "+e, e); - } - notificationHandlerThread = null; - } - } private void setupLocalInfluxDB() { Log.d(TAG, "setupLocalInfluxDB"); @@ -492,6 +598,20 @@ private void stopLocalInfluxDB() { } } + Runnable monitorInfluxDBConnectionStatus = new Runnable() { + @Override + public void run() { + if (ic == null) return; + boolean newInfluxConnectionStatus = ic.ping(); + Log.d(TAG, "run: monitorInfluxDBConnectionStatus: "+newInfluxConnectionStatus); + if(newInfluxConnectionStatus != influxConnectionStatus) { + influxConnectionStatus = newInfluxConnectionStatus; + updateNotification(); + }; + remoteInfluxHandler.postDelayed(this, interval); + } + }; + /** * initialize a new remote influxDB connection */ @@ -499,10 +619,12 @@ private void setupRemoteInfluxDB() { Log.d(TAG, "setupRemoteInfluxDB"); ic = InfluxdbConnections.getRicInstance(getApplicationContext()); Objects.requireNonNull(ic).open_write_api(); + getInfluxDBConnectionStatus(); remoteInfluxHandlerThread = new HandlerThread("RemoteInfluxHandlerThread"); remoteInfluxHandlerThread.start(); remoteInfluxHandler = new Handler(Objects.requireNonNull(remoteInfluxHandlerThread.getLooper())); remoteInfluxHandler.post(RemoteInfluxUpdate); + remoteInfluxHandler.post(monitorInfluxDBConnectionStatus); ImageView log_status = gv.getLog_status(); if (log_status != null) { gv.getLog_status().setColorFilter(Color.argb(255, 255, 0, 0)); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java index 3062356b..0f940278 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java @@ -69,6 +69,7 @@ public class MainActivity extends AppCompatActivity implements PreferenceFragmen public boolean cp = false; public boolean feature_telephony = false; Intent loggingServiceIntent; + Intent notificationServiceIntent; NavController navController; private Handler requestCellInfoUpdateHandler; private HandlerThread requestCellInfoUpdateHandlerThread; @@ -213,6 +214,21 @@ protected void onCreate(Bundle savedInstanceState) { } } }, SPType.logging_sp); + + notificationServiceIntent = new Intent(context, NotificationService.class); + if(spg.getSharedPreference(SPType.default_sp).getBoolean("enable_radio_notification", false)){ + context.startService(notificationServiceIntent); + } + spg.setListener((prefs, key) -> { + if(Objects.equals(key, "enable_radio_notification")){ + if(prefs.getBoolean(key, false)){ + context.startService(notificationServiceIntent); + } else { + context.stopService(notificationServiceIntent); + } + } + }, SPType.default_sp); + getAppSignature(); gv.setGit_hash(getString(R.string.git_hash)); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/NotificationService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/NotificationService.java new file mode 100644 index 00000000..894e3f30 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/NotificationService.java @@ -0,0 +1,158 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.graphics.Color; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; + +import com.influxdb.client.domain.Run; + +import java.util.Objects; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.DataProvider; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; + +public class NotificationService extends Service { + + private static final String TAG = "NotificationService"; + public NotificationManager nm; + NotificationCompat.Builder builder; + private Handler notificationHandler; + private HandlerThread notificationHandlerThread; + private SharedPreferencesGrouper spg; + + private GlobalVars gv; + private DataProvider dp; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private void setupNotificationUpdate() { + Log.d(TAG, "setupNotificationUpdate"); + notificationHandlerThread = new HandlerThread("NotificationHandlerThread"); + notificationHandlerThread.start(); + notificationHandler = new Handler(Objects.requireNonNull(notificationHandlerThread.getLooper())); + notificationHandler.post(servingCellNotificaiton); + } + + private void stopNotificationUpdate() { + Log.d(TAG, "stopNotificationUpdate"); + notificationHandler.removeCallbacks(servingCellNotificaiton); + //builder.setContentText(null); + //nm.notify(1, builder.build()); + nm.cancel(4); + + if (notificationHandlerThread != null) { + notificationHandlerThread.quitSafely(); + try { + notificationHandlerThread.join(); + } catch (InterruptedException e) { + Log.e(TAG, "Exception happened!! "+e, e); + } + notificationHandlerThread = null; + } + onDestroy(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + gv = GlobalVars.getInstance(); + dp = gv.get_dp(); + nm = getSystemService(NotificationManager.class); + spg = SharedPreferencesGrouper.getInstance(this); + spg.setListener((prefs, key) -> { + if (prefs.getBoolean("enable_radio_notification", false)) { + setupNotificationUpdate(); + } else { + stopNotificationUpdate(); + } + + }, SPType.default_sp); + setupNotification(); + startForeground(4, builder.build()); + + return START_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + private void setupNotification() { + // create intent for notifications + Intent notificationIntent = new Intent(this, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); + + StringBuilder s = getStringBuilder(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // create notification + builder = new NotificationCompat.Builder(this, "OMNT_notification_channel") + .setContentTitle(getText(R.string.cell_notifcation)) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setColor(Color.WHITE) + .setContentIntent(pendingIntent) + // prevent to swipe the notification away + .setOngoing(true) + .setOnlyAlertOnce(true) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)) + // don't wait 10 seconds to show the notification + .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE); + } else { + // create notification + builder = new NotificationCompat.Builder(this, "OMNT_notification_channel") + .setContentTitle(getText(R.string.cell_notifcation)) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setColor(Color.WHITE) + .setContentIntent(pendingIntent) + .setOnlyAlertOnce(true) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)) + // prevent to swipe the notification away + .setOngoing(true); + } + setupNotificationUpdate(); + } + private StringBuilder getStringBuilder(){ + if(dp == null) return new StringBuilder(); + if(dp.getRegisteredCells() == null) return new StringBuilder(); + StringBuilder s = dp.getRegisteredCells().get(0).getStringBuilder(); + return s; + } + private void updateNotification(){ + StringBuilder s = getStringBuilder(); + builder.setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)); + nm.notify(4, builder.build()); + } + + Runnable servingCellNotificaiton = new Runnable() { + @Override + public void run() { + updateNotification(); + notificationHandler.postDelayed(servingCellNotificaiton, 1000); + + } + }; + + @Override + public void onCreate() { + super.onCreate(); + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8faa0bd4..c3cf36bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,7 +17,7 @@ iPerf3 Send -c 172.17.0.1 - OpenMobileNetworkToolkit logging + Logging Service This app is provided by NGNI a department of Fraunhofer FOKUS. \n\nhttps://www.fokus.fraunhofer.de/go/ngni \n\nThis software is licensed under BSD 3-Clause Clear License https://spdx.org/licenses/BSD-3-Clause-Clear.html \n\nAuthors: \n\nPeter Hasse \nMohsin Nisar \nJohann Hackler OpenMobileNetworkToolkit @@ -254,5 +254,8 @@ Standard Channel Bandwidth Security Type + Serving Cell Parameter: PCI, RSRP... + Enable Cell Notification + Serving Cell \ No newline at end of file diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index dc774fe2..6af95295 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -15,13 +15,19 @@ android:title="@string/home_screen_settings" app:iconSpaceReserved="false"> - + + - +