first commit

This commit is contained in:
TheUnrealDragon 2026-04-01 18:33:19 +05:30
commit 9bfa1e11fe
11 changed files with 1751 additions and 0 deletions

View file

@ -0,0 +1,68 @@
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.qtproject.example.appwaterLevelSensor"
android:installLocation="auto"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true" />
<application
android:name="org.qtproject.qt.android.bindings.QtApplication"
android:hardwareAccelerated="true"
android:label="appwaterLevelSensor"
android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:fullBackupOnly="false">
<service android:name=".WaterLevelService"
android:foregroundServiceType="specialUse"
android:exported="true">
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Monitoring water levels via local network UDP packets for real-time sensor alerts." />
<meta-data android:name="android.app.lib_name" android:value="service"/>
<meta-data android:name="android.app.background_running" android:value="true"/>
</service>
<activity
android:name="org.qtproject.qt.android.bindings.QtActivity"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:label="appwaterLevelSensor"
android:launchMode="singleTop"
android:screenOrientation="unspecified"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="appwaterLevelSensor" />
<meta-data
android:name="android.app.arguments"
android:value="" />
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.qtprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/qtprovider_paths"/>
</provider>
</application>
</manifest>

83
android/build.gradle Normal file
View file

@ -0,0 +1,83 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
//noinspection AndroidGradlePluginVersion
classpath 'com.android.tools.build:gradle:8.8.0'
}
}
repositories {
google()
mavenCentral()
}
apply plugin: qtGradlePluginType
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
//noinspection GradleDependency
implementation 'androidx.core:core:1.16.0'
}
android {
/*******************************************************
* The following variables:
* - androidBuildToolsVersion,
* - androidCompileSdkVersion
* - qtAndroidDir - holds the path to qt android files
* needed to build any Qt application
* on Android.
* - qtGradlePluginType - whether to build an app or a library
*
* are defined in gradle.properties file. This file is
* updated by QtCreator and androiddeployqt tools.
* Changing them manually might break the compilation!
*******************************************************/
namespace = androidPackageName
compileSdkVersion androidCompileSdkVersion
buildToolsVersion androidBuildToolsVersion
ndkVersion = androidNdkVersion
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
res.srcDirs = [qtAndroidDir + '/res', 'res']
resources.srcDirs = ['resources']
renderscript.srcDirs = ['src']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
tasks.withType(JavaCompile) {
options.incremental = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError = false
}
aaptOptions {
// Do not compress Qt binary resources file
noCompress 'rcc'
}
defaultConfig {
resConfig "en"
minSdkVersion qtMinSdkVersion
targetSdkVersion qtTargetSdkVersion
ndk.abiFilters = qtTargetAbiList.split(",")
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1,17 @@
package org.qtproject.example.appwaterLevelSensor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class WaterLevelReceiver extends BroadcastReceiver {
public native static void updateWaterLevel(byte[] data);
@Override
public void onReceive(Context context, Intent intent) {
if ("com.example.WATER_LEVEL_UPDATE".equals(intent.getAction())) {
byte[] data = intent.getByteArrayExtra("level_data");
updateWaterLevel(data);
}
}
}

View file

@ -0,0 +1,210 @@
package org.qtproject.example.appwaterLevelSensor;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.BitmapFactory;
import android.app.NotificationChannel;
import org.qtproject.qt.android.bindings.QtService;
import android.util.Log;
import android.content.Intent;
import java.lang.Runnable;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.*;
import org.qtproject.qt.android.bindings.QtActivity;
import android.app.Service;
import java.time.Instant;
import java.time.Duration;
public class WaterLevelService extends Service {
private static float alert_thres_distance = 1000000;
public class UDPCommandClient implements Runnable {
private DatagramSocket socket_cmd_recv;
private DatagramSocket socket_cmd_send;
@Override
public void run() {
Log.d("UDP Service", "Command thread initialising");
try {
socket_cmd_recv = new DatagramSocket(8178, InetAddress.getByName("localhost"));
socket_cmd_send = new DatagramSocket(8179);
Log.d("UDP Service", "Created command thread sockets");
while (!Thread.currentThread().isInterrupted()) {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket_cmd_recv.receive(packet);
String str = new String(buffer, StandardCharsets.UTF_8);
if(str.startsWith("<SET NAME=ALERT VALUE=")) {
str = str.replace("<SET NAME=ALERT VALUE=", "");
str = str.replace("=", "");
str = str.replace(">", "");
alert_thres_distance = Float.parseFloat(str);
}
Log.d("UDP Service ", "Received command packet " + str);
}
}
catch (IOException e) {
Log.e("UDP Service", "Socket Error", e);
}
}
}
public class UDPClient implements Runnable {
private DatagramSocket socket_recv;
private DatagramSocket socket_send;
private Instant prevAlertTimestamp;
private boolean started = false;
@Override
public void run() {
Log.d("UDP Service", "Thread initialising");
android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) getSystemService(Context.WIFI_SERVICE);
android.net.wifi.WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("water_level_lock");
android.os.PowerManager pm = (android.os.PowerManager) getSystemService(Context.POWER_SERVICE);
android.os.PowerManager.WakeLock wakeLock = pm.newWakeLock(android.os.PowerManager.PARTIAL_WAKE_LOCK, "WaterLevel:WakeLock");
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String alertChannelId = "water_alert_channel";
NotificationChannel channel = new NotificationChannel(
alertChannelId,
"Water Level Alerts",
NotificationManager.IMPORTANCE_HIGH
);
manager.createNotificationChannel(channel);
try {
multicastLock.acquire();
wakeLock.acquire();
socket_recv = new DatagramSocket(8176);
socket_send = new DatagramSocket(8177);
socket_recv.setBroadcast(true);
Log.d("UDP Service", "Created Sockets");
while (!Thread.currentThread().isInterrupted()) {
byte[] buffer = new byte[4];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket_recv.receive(packet);
float f = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getFloat();
Log.d("UDP Service ", "Received packet: " + f);
Log.d("UDP Service ", "Threshold is: " + alert_thres_distance);
boolean duration_passed = false;
if(!started) {
duration_passed = true;
prevAlertTimestamp = Instant.now();
}
else {
Instant currentTimestamp = Instant.now();
Duration duration = Duration.between(prevAlertTimestamp, currentTimestamp);
if(duration.toMinutes() > 30) {
duration_passed = true;
}
prevAlertTimestamp = currentTimestamp;
}
if(f > alert_thres_distance && alert_thres_distance < 999999 && duration_passed) {
Notification.Builder builder = new Notification.Builder(WaterLevelService.this, alertChannelId)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setContentTitle("Water Level Sensor")
.setContentText("Water Level is below alert threshold")
.setPriority(Notification.PRIORITY_HIGH);
manager.notify(2, builder.build());
Log.d("UDP Service", "Notification sent");
}
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 8180);
socket_send.send(send_packet);
Log.d("UDP Service ", "Sent packet");
}
}
catch (IOException e) {
Log.e("UDP Service", "Socket Error", e);
} finally {
if (multicastLock.isHeld())
multicastLock.release();
if (wakeLock.isHeld())
wakeLock.release();
if (socket_recv != null)
socket_recv.close();
}
}
}
public void startWaterLevelService() {
Log.d("UDP Service", "Starting the service from Activity");
Intent intent = new Intent(this, WaterLevelService.class);
startForegroundService(intent);
}
public WaterLevelService() {
super();
Log.i("UDP Service", "Class is created");
}
@Override
public android.os.IBinder onBind(android.content.Intent intent) { return null; }
@Override
public void onCreate() {
super.onCreate();
Notification notification = createNotification();
startForeground(1, notification);
Log.i("UDP Service", "Creating Service");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("UDP Service", "Destroying Service");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = createNotification();
startForeground(1, notification);
Log.d("UDP Service", "Actually starting the thread");
int ret = super.onStartCommand(intent, flags, startId);
(new Thread(new UDPClient())).start();
(new Thread(new UDPCommandClient())).start();
return START_STICKY;
}
private Notification createNotification() {
String channelId = "water_level_channel";
NotificationManager manager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(
channelId,
"Water Level Service",
NotificationManager.IMPORTANCE_LOW
);
manager.createNotificationChannel(channel);
return new Notification.Builder(this, channelId)
.setContentTitle("Water Level Sensor Running")
.setContentText("Monitoring water level...")
.setSmallIcon(android.R.drawable.ic_menu_info_details)
.build();
}
public static void startQtAndroidService(QtActivity activity) {
Log.d("UDP Service", "Starting the service");
Intent intent = new Intent(activity, WaterLevelService.class);
activity.startForegroundService(intent);
}
}

View file

@ -0,0 +1,19 @@
package org.qtproject.example.appwaterLevelSensor;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import org.qtproject.qt.android.bindings.QtActivity;
public class WaterLevelServiceStarter {
public static void startService(Context context) {
Log.d("UDP Service", "Starting service via QtActivity instance");
Intent intent = new Intent(context, WaterLevelService.class);
context.startForegroundService(intent);
}
}