This commit is contained in:
TheUnrealDragon 2026-04-17 15:43:25 +05:30
commit e6d5589cad
2 changed files with 411 additions and 105 deletions

View file

@ -25,25 +25,87 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;
import android.widget.Toast;
import android.os.IBinder;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
public class WaterLevelService extends Service {
private static float alert_thres_distance = 1000000;
private boolean bits_flipped = false;
private String mode = "";
private String url = "";
private Thread udpThread;
private Thread cmdThread;
private boolean resetBinds = false;
private static boolean bits_flipped = false;
private static String mode = "";
private static String url = "";
private static Thread udpThread;
private static Thread cmdThread;
private static boolean resetBinds = false;
private final IBinder binder = new LocalBinder();
final Messenger mMessenger = new Messenger(new IncomingHandler());
public static final int MSG_RESTART_THREADS = 1;
public synchronized boolean checkBound() {
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RESTART_THREADS:
Log.d("UDP Service MainThread", "Received IPC request to restart threads");
restartThreads();
break;
default:
super.handleMessage(msg);
}
}
}
public synchronized void restartThreads() {
Log.d("UDP Service MainThread", "In synchronized thread stopper.");
udpThread.interrupt();
cmdThread.interrupt();
try {
udpThread.join();
cmdThread.join();
} catch (InterruptedException e) {
Log.d("UDP Service MainThread", "Thread joining was interrupted because of: " + e);
}
new Thread(new
Runnable() {
@Override
public void run() {
try {
// Move your socket and thread starting logic here
if (udpThread == null || !udpThread.isAlive()) {
udpThread = new Thread(new UDPClient());
udpThread.start();
}
if (cmdThread == null || !cmdThread.isAlive()) {
cmdThread = new Thread(new UDPCommandClient());
cmdThread.start();
}
} catch (Exception e) {
Log.e("UDP Service MainThread", "Restarting the threads", e);
}
}
}).start();
Log.d("UDP Service MainThread", "Actually restarting the thread");
}
public static synchronized boolean checkBound() {
return resetBinds;
}
public synchronized void setBound(boolean value) {
public static synchronized void setBound(boolean value) {
resetBinds = value;
}
public class LocalBinder extends android.os.Binder {
WaterLevelService getService() {
return WaterLevelService.this;
}
}
public class UDPCommandClient implements Runnable {
private DatagramSocket socket_cmd_recv;
private DatagramSocket socket_cmd_send;
@ -51,7 +113,7 @@ public class WaterLevelService extends Service {
@Override
public void run() {
Log.d("UDP Service", "Command thread initialising");
Log.d("UDP Service CommandThread", "Command thread initialising");
try {
socket_cmd_recv = new DatagramSocket(null);
socket_cmd_send = new DatagramSocket(null);
@ -59,15 +121,30 @@ public class WaterLevelService extends Service {
socket_cmd_recv.setReuseAddress(true);
socket_cmd_send.setReuseAddress(true);
socket_cmd_recv.bind(new InetSocketAddress(8178));
socket_cmd_send.bind(new InetSocketAddress(8179));
Log.d("UDP Service", "Created command thread sockets");
socket_cmd_send.bind(new InetSocketAddress(8187));
boolean not_send_set = true;
Log.d("UDP Service CommandThread", "Created command thread sockets");
while (!Thread.currentThread().isInterrupted()) {
if(socket_cmd_recv.isClosed()) {
socket_cmd_recv.bind(new InetSocketAddress(8178));
}
if(socket_cmd_send.isClosed()) {
socket_cmd_send.bind(new InetSocketAddress(8179));
socket_cmd_send.bind(new InetSocketAddress(8187));
}
if(not_send_set) {
String s_data = new String("<SET>");
byte[] buff_s = s_data.getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(buff_s, buff_s.length, InetAddress.getByName("127.0.0.1"), 8186);
try {
socket_cmd_send.connect(InetAddress.getByName("127.0.0.1"), 8186);
socket_cmd_send.send(packet);
} catch(Exception e) {
Log.d("UDP Service CommandThread", "Failed to send data to client due to: " + e);
}
Log.d("UDP Service CommandThread", "Sent set message to client");
}
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
@ -76,7 +153,8 @@ public class WaterLevelService extends Service {
continue;
}
String str = new String(buffer, StandardCharsets.UTF_8);
Log.d("UDP Service ", "Received command packet " + str);
Log.d("UDP Service CommandThread", "Received command packet " + str);
not_send_set = false;
if(str.startsWith("<SET NAME=ALERT VALUE=")) {
str = str.replace("<SET NAME=ALERT VALUE=", "");
str = str.replace("=", "");
@ -86,10 +164,10 @@ public class WaterLevelService extends Service {
if(!checkBound())
{
setBound(true);
Log.d("UDP Service ", "Set Bound to True");
Log.d("UDP Service CommandThread", "Set Bound to True");
}
else {
Log.d("UDP Service ", "Set Bound is False");
Log.d("UDP Service CommandThread", "Set Bound is False");
}
}
@ -98,7 +176,7 @@ public class WaterLevelService extends Service {
str = str.replace("<SET NAME=BITS_FLIPPED VALUE=", "");
str = str.replace("=", "");
str = str.replace(">", "");
Log.d("UDP Service ", "Flipping " + str);
Log.d("UDP Service CommandThread", "Flipping " + str);
if(str.toLowerCase() == "false") {
bits_flipped = false;
}
@ -110,21 +188,21 @@ public class WaterLevelService extends Service {
str = str.replace("<SET NAME=MODE VALUE=", "");
str = str.replace("=", "");
str = str.replace(">", "");
Log.d("UDP Service ", "Mode " + str);
Log.d("UDP Service CommandThread", "Mode " + str);
mode = str.toLowerCase();
}
else if(str.startsWith("<SET NAME=URL VALUE=")) {
str = str.replace("<SET NAME=URL VALUE=", "");
str = str.replace("=", "");
str = str.replace(">", "");
Log.d("UDP Service ", "Url " + str);
Log.d("UDP Service CommandThread", "Url " + str);
url = str.toLowerCase();
}
}
}
catch (IOException e) {
// showToast("IOException: " + e);
Log.e("UDP Service", "IOException Error" + e);
Log.e("UDP Service CommandThread", "IOException Error" + e);
}
}
@ -134,11 +212,12 @@ public class WaterLevelService extends Service {
private DatagramSocket socket_recv;
private DatagramSocket socket_send;
private Instant prevAlertTimestamp;
private InetAddress address;
private boolean started = false;
@Override
public void run() {
Log.d("UDP Service", "Client Thread initialising");
Log.d("UDP Service ClientThread", "Client 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.net.wifi.WifiManager.WifiLock wifiLock = wifi.createWifiLock(android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF, "WaterLevel:WifiLock");
@ -167,16 +246,19 @@ public class WaterLevelService extends Service {
socket_send.setReuseAddress(true);
socket_send.bind(new InetSocketAddress(8177));
socket_recv.bind(new InetSocketAddress(8176));
Log.d("UDP Service", "Created Sockets");
Log.d("UDP Service ClientThread", "Created Sockets");
int count = 0;
while (!Thread.currentThread().isInterrupted()) {
count++;
if(count == 3) {
Log.i("UDP Service", "Thread is running with mode: " + mode);
Log.i("UDP Service ClientThread", "Thread is running with mode: " + mode);
count = 0;
}
if(checkBound()) {
Log.i("UDP Service", "Reconnecting sockets");
Log.i("UDP Service ClientThread", "Reconnecting sockets");
this.address = InetAddress.getByName("127.0.0.1");
socket_recv.disconnect();
socket_send.disconnect();
socket_recv.close();
socket_send.close();
socket_recv = null;
@ -190,7 +272,7 @@ public class WaterLevelService extends Service {
socket_send.bind(new InetSocketAddress(8177));
socket_recv.bind(new InetSocketAddress(8176));
setBound(false);
Log.i("UDP Service", "Reconnected sockets");
Log.i("UDP Service ClientThread", "Reconnected sockets");
}
// if(checkBound()) {
// Log.i("UDP Service", "Reset socket binds: " + mode);
@ -238,9 +320,10 @@ public class WaterLevelService extends Service {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
continue;
Log.d("UDP Service ClientThread", "Thread exiting due to interrupt.");
return;
}
Log.d("UDP Service", "Http String Url: " + url);
Log.d("UDP Service ClientThread", "Http String Url: " + url);
URL t_url = new URL(url);
HttpURLConnection con = (HttpURLConnection) t_url.openConnection();
con.setRequestMethod("GET");
@ -248,7 +331,7 @@ public class WaterLevelService extends Service {
con.setReadTimeout(5000);
con.setInstanceFollowRedirects(true);
int status = con.getResponseCode();
Log.d("UDP Service", "Got status from http: " + status);
Log.d("UDP Service ClientThread", "Got status from http: " + status);
if(status == 200) {
BufferedReader streamReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String data = streamReader.readLine();
@ -258,10 +341,10 @@ public class WaterLevelService extends Service {
float f = (float ) arr.getDouble(0);
updated = obj.getString("updated_on");
buffer = ByteBuffer.allocate(4).putFloat(f).array();
Log.d("UDP Service", "Got value from http: " + f);
Log.d("UDP Service", "Last updated on: " + updated);
Log.d("UDP Service ClientThread", "Got value from http: " + f);
Log.d("UDP Service ClientThread", "Last updated on: " + updated);
} catch (JSONException e) {
Log.e("UDP Service", "Invalid Json");
Log.e("UDP Service ClientThread", "Invalid Json");
// showToast("Invalid Json" + e);
continue;
}
@ -273,12 +356,13 @@ public class WaterLevelService extends Service {
}
}
else {
Log.d("UDP Service", "Invalid mode: " + mode);
Log.d("UDP Service ClientThread", "Invalid mode: " + mode);
// showToast("Invalid mode: " + mode);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
continue;
Log.d("UDP Service ClientThread", "Thread exiting due to interrupt.");
return;
}
continue;
}
@ -289,8 +373,8 @@ public class WaterLevelService extends Service {
else {
f = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN).getFloat();
}
Log.d("UDP Service ", "Received packet: " + f);
Log.d("UDP Service ", "Threshold is: " + alert_thres_distance);
Log.d("UDP Service ClientThread", "Received packet: " + f);
Log.d("UDP Service ClientThread", "Threshold is: " + alert_thres_distance);
boolean duration_passed = false;
if(!started) {
duration_passed = true;
@ -311,7 +395,7 @@ public class WaterLevelService extends Service {
.setContentText("Water Level is below alert threshold")
.setPriority(Notification.PRIORITY_LOW);
manager.notify(2, builder.build());
Log.d("UDP Service", "Notification sent");
Log.d("UDP Service ClientThread", "Notification sent");
if(!started) {
started = true;
}
@ -319,20 +403,20 @@ public class WaterLevelService extends Service {
if(socket_send.isClosed()) {
socket_send.bind(new InetSocketAddress(8177));
}
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 8180);
DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("127.0.0.1"), 8180);
socket_send.send(send_packet);
Log.d("UDP Service ", "Sent packet");
Log.d("UDP Service ClientThread", "Sent packet");
if(mode.equals("http")) {
byte[] buff2 = updated.getBytes(StandardCharsets.UTF_8);
DatagramPacket send_packet_2 = new DatagramPacket(buff2, buff2.length, InetAddress.getByName("localhost"), 8185);
DatagramPacket send_packet_2 = new DatagramPacket(buff2, buff2.length, InetAddress.getByName("127.0.0.1"), 8185);
socket_send.send(send_packet_2);
Log.d("UDP Service ", "Sent last updated packet");
Log.d("UDP Service ClientThread", "Sent last updated packet");
}
}
}
catch (IOException e) {
// showToast("IOException: " + e);
Log.e("UDP Service", "IOException Error" + e);
Log.e("UDP Service ClientThread", "IOException Error" + e);
} finally {
if (wifiLock.isHeld())
wifiLock.release();
@ -347,7 +431,7 @@ public class WaterLevelService extends Service {
}
public void startWaterLevelService() {
Log.d("UDP Service", "Starting the service from Activity");
Log.d("UDP Service MainThread", "Starting the service from Activity");
Intent intent = new Intent(this, WaterLevelService.class);
@ -355,25 +439,25 @@ public class WaterLevelService extends Service {
}
public WaterLevelService() {
super();
Log.i("UDP Service", "Class is created");
Log.i("UDP Service MainThread", "Class is created");
}
@Override
public android.os.IBinder onBind(android.content.Intent intent) { return null; }
public android.os.IBinder onBind(android.content.Intent intent) { return mMessenger.getBinder(); }
@Override
public void onCreate() {
super.onCreate();
Notification notification = createNotification();
startForeground(1, notification);
Log.i("UDP Service", "Creating Service");
Log.i("UDP Service MainThread", "Creating Service");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("UDP Service", "Destroying Service");
Log.i("UDP Service MainThread", "Destroying Service");
}
@Override
@ -383,7 +467,7 @@ public class WaterLevelService extends Service {
if (intent == null) {
Log.w("UDP Service", "Service restarted with null intent. Stopping to avoid crash.");
Log.w("UDP Service MainThread", "Service restarted with null intent. Stopping to avoid crash.");
stopSelf();
return START_NOT_STICKY;
}
@ -402,12 +486,12 @@ public class WaterLevelService extends Service {
cmdThread.start();
}
} catch (Exception e) {
Log.e("UDP Service", "Error starting threads", e);
Log.e("UDP Service MainThread", "Error starting threads", e);
}
}
}).start();
Log.d("UDP Service", "Actually starting the thread");
Log.d("UDP Service MainThread", "Actually starting the thread");
int ret = super.onStartCommand(intent, flags, startId);
@ -444,7 +528,7 @@ public class WaterLevelService extends Service {
}
public static void startQtAndroidService(QtActivity activity) {
Log.d("UDP Service", "Starting the service");
Log.d("UDP Service MainThread", "Starting the service");
Intent intent = new Intent(activity, WaterLevelService.class);
activity.startForegroundService(intent);

View file

@ -10,9 +10,51 @@ import android.app.ActivityManager.RunningServiceInfo;
import org.qtproject.qt.android.bindings.QtActivity;
import android.os.Handler;
import android.os.Looper;
import android.content.ServiceConnection;
import android.content.ComponentName;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
public class WaterLevelServiceStarter {
private static Messenger mServiceMessenger = null;
private static boolean mBound = false;
private static boolean restart_bind = false;
private static ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mServiceMessenger = new Messenger(service);
mBound = true;
Log.d("UDP Service StarterThread", "Connected to Service object reference");
if(restart_bind)
{
sendRestartMessage();
Log.d("UDP Service StarterThread", "Restart Threads in Service.");
}
restart_bind = false;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mServiceMessenger = null;
mBound = false;
}
};
public static void startAndBindService(Context context) {
Intent intent = new Intent(context, WaterLevelService.class);
context.startForegroundService(intent);
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
public static void bindService(Context context) {
restart_bind = true;
Intent intent = new Intent(context, WaterLevelService.class);
context.bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
private static boolean isMyServiceRunning(Class<?> serviceClass, Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@ -24,6 +66,7 @@ public class WaterLevelServiceStarter {
return false;
}
private static int getServicePid(Class<?> serviceClass, Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
@ -34,6 +77,20 @@ public class WaterLevelServiceStarter {
return 0;
}
public static void sendRestartMessage() {
if (!mBound || mServiceMessenger == null) {
Log.d("UDP Service StarterThread", "Service is not running.");
}
try {
Message msg = Message.obtain(null, WaterLevelService.MSG_RESTART_THREADS);
mServiceMessenger.send(msg);
Log.d("UDP Service StarterThread", "Sent restart signal to remote process");
} catch (RemoteException e) {
Log.e("UDP Service StarterThread", "Failed to send message", e);
}
}
public static void startService(Context context) {
// Log.d("UDP Service", "Starting service via QtActivity instance");
@ -45,15 +102,16 @@ public class WaterLevelServiceStarter {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
if (!isMyServiceRunning(WaterLevelService.class, context)) {
Log.d("UDP Service", "Starting service safely on Main Looper");
Intent intent = new Intent(context, WaterLevelService.class);
context.startForegroundService(intent);
Log.d("UDP Service StarterThread", "Starting service safely on Main Looper");
startAndBindService(context);
}
else {
Log.d("UDP Service", "Service already running");
Log.d("UDP Service StarterThread", "Service already running, so restarting the threads.");
bindService(context);
}
Log.d("UDP Service", "Background service running with pid: " + getServicePid(WaterLevelService.class, context));
Log.d("UDP Service StarterThread", "Background service running with pid: " + getServicePid(WaterLevelService.class, context));
}
});
}