Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom URL does not work if Wifi/Mobile data is not enabled, but bluetooth PAN is available #1197

Open
rotarurazvan07 opened this issue Feb 4, 2025 · 4 comments

Comments

@rotarurazvan07
Copy link

Environement:
Phone that has disabled mobile data and wifi, but has a bluetooth tetering enabled with another device that runs a flask server.
Bug description:
The GET request is never executed or it fails out (I haven't investigated much)
My local fix:
Open socket and let Android handle the connection:

BluetoothDirectClient class that has the sendRequest function

package com.mendhak.gpslogger.senders.customurl;

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BluetoothDirectClient {

    public static void sendRequest(
            String url
    ) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Handler handler = new Handler(Looper.getMainLooper());

        executor.execute(() -> {
            URI uri = null;
            try {
                uri = new URI(url);
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
            // Extract my info
            String clientIp = uri.getHost();
            int port = uri.getPort();
            String path = uri.getRawPath();
            if (uri.getRawQuery() != null) {
                path += "?" + uri.getRawQuery();
            }
            // Write on socket, let Android handle connection
            try (Socket socket = new Socket(clientIp, port)) {
                OutputStream outputStream = socket.getOutputStream();
                String httpRequest = String.format(
                        "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n",
                        path,
                        clientIp
                );
                outputStream.write(httpRequest.getBytes());
                outputStream.flush();

                // Read response
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line).append("\n");
                }
                Log.d("Bluetooth", "Response:\n" + response);
            } catch (IOException e) {
                Log.e("Bluetooth", "Error: " + e.getMessage());
            }

            handler.post(() -> {
                //UI Thread work here
            });
        });
    }
}

Then, I called it in GpsLoggerService at onLocationChanged, as i couldn't reach the doWork function inside the CustomUrlWorker

String url = "http://IP:PORT/PATH?lat=%LAT&long=%LON&alt=%ALT&time=%TIME";
url = url.replace("%LAT", String.valueOf(loc.getLatitude()));
url = url.replace("%LON", String.valueOf(loc.getLongitude()));
url = url.replace("%ALT", String.valueOf(loc.getAltitude()));
url = url.replace("%TIME", String.valueOf(Strings.getUrlEncodedString(Strings.getIsoDateTime(new Date(loc.getTime())))));

BluetoothDirectClient.sendRequest(
      url
);

Mind you, I am in no way an Android expert, and I have not tested much my solution, just wanted to expose a limitation :)

@mendhak
Copy link
Owner

mendhak commented Feb 4, 2025

I haven't encountered this kind of a setup before so it sounds very specific/niche to me. I don't think it's catered to in the Android WorkRequest setup.

In the app the Custom URL has a network requirement,

Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(PreferenceHelper.getInstance().shouldAutoSendOnWifiOnly() ? NetworkType.UNMETERED: NetworkType.CONNECTED)
.build();

That NetworkType for either condition is from this page: https://developer.android.com/reference/androidx/work/NetworkType The purpose behind the network check is so that the jobs don't get queued up without a working connection.

And I'm assuming there must be (or hope there is) some kind of network connectivity test that happens before the system returns that connected = true.

Your local fix looks quite good, I wonder if there's a simpler way which is to remove the constraints from the builder:

OneTimeWorkRequest workRequest = new OneTimeWorkRequest
.Builder(workerClass)
.setConstraints(constraints)
.setInitialDelay(1, java.util.concurrent.TimeUnit.SECONDS)

And that could simply mean "just send it, I don't care for network connectivity".

@rotarurazvan07
Copy link
Author

I can try this tomorrow, without constraints. Thanks a lot.
I will report back :)

@nckpln
Copy link

nckpln commented Feb 10, 2025

Same issue here. I run into this problem when I try logging to my local web server 192.168.. through WiFi and it works perfectly fine when the internet access for this subnet is enabled on a router, but if it is not, the logging to the local server stops working. Additionally, the same thing happens if I block internet access in Android using AFWall. The issue was not present in v.130 and below.

@mendhak
Copy link
Owner

mendhak commented Feb 11, 2025

Then for sure it must be related to WorkManager's network 'detection' logic. 131 is when Workmanager was introduced, since I had to move away from the old library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants