Reputation: 77
My project is to make a rear view camera using an old USB webcam and a Raspberry Pi.
I plugged the cam to the pi and using "motion", and I can access the live video with a browser (http://<ip-address>:8081
), when I am on the same network as the Pi.
For that, I turned my Pi to a wifi hotspot, in order to be in the same network with my phone to access the video.
But: After I created an application with Android Studio, with a WebView to open the video link, I get a ERR_CONNECTION_REFUSED
when mobile data is enabled. Since the Wifi-Network doesn't get used if no internet connection is detected.
I don't want to manually disable it each time I want to use it, I want the application to use the Wi-Fi ONLY.
I managed to auto connect to the pi WiFi using this code :
WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
.setSsid("Wifi-Fourcon")
.setWpa2Passphrase("1234567890")
.build();
final NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) // we want WiFi
.setNetworkSpecifier(specifier) // we want _our_ network
.build();
ConnectivityManager connectivityManager = (ConnectivityManager)this.getSystemService(CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(request,
I tried to add
.removeTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
But same result.
I also tried to disable mobile data with
setMobileDataEnabled()
But we cannot use this method anymore..
Upvotes: 2
Views: 2749
Reputation: 4544
So I'm assuming the problem here is that the Wifi connection doesn't actually provide internet, so android ignores the connection for web requests.
Edit: After reading through the docs, the method bindProcessToNetwork seems to fit the use-case much better. It will limit the whole process to only use that specific network. I have once again not tested this, but it should be easily implemented by calling the method right in onAvailable
and call it with null
in onLost
if you want to reverse the binding if needed. Existing sockets won't be forced, so the safest way would be to initialize the WebView only after binding to the network.
One can circumvent this by overriding how the WebView loads it's request and force it to use the connection of your Network request. A complete solution would probably look like this, altough I have not tested it. Let me know if this works:
Network networkInstance;
void getNetwork(Context context) {
final NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) // we want WiFi
.setNetworkSpecifier("foobar") // we want _our_ network
.build();
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(request, new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
networkInstance = network;
loadWebView();
}
@Override
public void onLost(@NonNull Network network) {
// Notify the user or something ...
super.onLost(network);
}
});
}
public void setupWebView(WebView webView) {
webView.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
if (networkInstance != null) {
try {
URL url = new URL(request.getUrl().toString());
HttpURLConnection connection = (HttpURLConnection) networkInstance.openConnection(url);
connection.setDoOutput(true);
connection.setRequestMethod(request.getMethod());
for (Map.Entry<String, String> header : request.getRequestHeaders().entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
int responseCode = connection.getResponseCode();
String responseMessage = connection.getResponseMessage();
String contentType = connection.getContentType();
String encoding = connection.getContentEncoding();
// Transform response headers from Map<String, List<String>> to Map<String, String>
HashMap<String, String> headerFields = new HashMap<>();
for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
headerFields.put(entry.getKey(), entry.getValue().get(0));
}
String[] contentTypeData = contentType.split(";\\s?");
contentType = contentTypeData[0];
if (contentTypeData.length > 1) {
encoding = contentTypeData[1];
}
if (contentType.contains("text") && encoding == null) {
encoding = "UTF-8";
}
InputStream inputStream;
try {
inputStream = connection.getInputStream();
} catch (Exception e) {
inputStream = connection.getErrorStream();
}
return new WebResourceResponse(
contentType,
encoding,
responseCode,
responseMessage,
headerFields,
inputStream
);
} catch (IOException e) {
e.printStackTrace();
}
}
return super.shouldInterceptRequest(view, request);
}
});
}
setupWebView
should be called once with the WebView instance to set the WebViewClient. (If you are already using a WebViewClient, just copy the overridden shouldInterceptRequest
method.)
Upvotes: 2
Reputation: 69
Google disabled the ability to modify critical Android features such as enable/disable mobile internet.
Upvotes: 0