Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download does not start on Android 9 when requesting a download from WLAN with no internet

A am working on an Android app which connects to a local flask server using WiFi. Then, the app displays images which are stored on the server (RPi3). A click on an image triggers a download request and I want the Android DownloadManager to enqueue the request and download the image. The WiFi network does not provide internet access.

So far, I have been able to test it on Android 6 and Android 8.1 devices and everything works fine. Testing on several Android 9 devices, the download does not start, but after disconnecting from the local network the failed attempts are shown.

Reading other threads about this, I have tried the following:

  • Setting the network security config as described here: Download Manger not working in Android Pie 9.0 (Xiaomi mi A2)
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

And added in the AndroidManifest.xml:

android:networkSecurityConfig="@xml/network_security_config"
  • Binding the network as described in the first answer here: Using a WiFi without Internet Connection

  • Playing with the options the DownloadManager.Request class provides, but they do not seem related to this problem:

.setRequiresCharging(false)
.setAllowedOverMetered(false)
.setAllowedOverRoaming(false)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, (String) url);
  • Checking again permissions. These are enabled:
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

This is the download request I create:

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url))
        .setTitle("Some Title")
        .setDescription("Downloading a file")
        .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        .setDestinationInExternalPublicDir("some_path", (String) url)
        .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
DownloadManager downloadManager= (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
downloadID = downloadManager.enqueue(request);

The Flask server (Python3) uses this the return the image:

    @app.route('/getFullImage/<image_file>')
    def get_full_image(image_file):
        log.debug("Client requests full image.")
        folder = os.path.join(app.root_path, "media_images")

        return flask.send_from_directory(directory=folder, filename=image_file, as_attachment=True)

As said, on Android 6 and 8.1, it worked fine but none of the Android 9 devices start the download. If there is any setting or method I do not know of, I would be happy to learn about it.

Thank you.

like image 917
jlee7 Avatar asked May 05 '19 16:05

jlee7


People also ask

How do I change my download settings from WIFI to mobile data?

Please go to “Settings” -> “Mobile Data Usage”, and turn the options (Stream and Download) off. You can also choose to go to your phone's mobile data settings, and disable Castbox to use your mobile data. For Android users, if you want to save more data, you can turn off "Show Episode Covers" as well.

How do Android apps connect to the Internet?

Before starting your application, Android studio will display following window to select an option where you want to run your Android application. Now just click on button, It will check internet connection as well as it will download image. Out would be as follows and it has fetch the logo from internet.


1 Answers

The key to this problem is to bind the process to the network. This allows your app to use wifi even if the wifi has no internet connectivity.

Here's my code, it's in kotlin but you can also convert it to Java

Just call this anywhere before trying to do a request. For me I placed this in the initialization of a singleton class that I use as network utility.

fun bindProcessToNetwork() {
    // Unbind the process from the network
    getConnectivityManager().bindProcessToNetwork(null)

    // Bind the process to the network
    getConnectivityManager().bindProcessToNetwork(getWifiNetwork())
}

These are the other methods I used in bindProcessToNetwork. You'll notice that I used a for loop to iterate through all network and try to determine which one is wifi instead of using connectionManager.activeNetworkInfo because that will return the cellular network when wifi has no internet connectivity.

private fun getConnectivityManager() : ConnectivityManager {
    val context = ApplicationContextProvider.getContext()
    return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}

private fun getWifiNetwork(): Network? {
    val networks = getConnectivityManager().allNetworks
    for (network in networks) {
        if (isNetworkWifi(network)) {
            return network
        }
    }
    return null
}

private fun isNetworkWifi(network: Network): Boolean {
    return this.getConnectivityManager().getNetworkCapabilities(network)
        .hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
}

You can read the documentation for WifiManager and ConnectivityManager for more information. There's a lot that has been deprecated in Level 28 (Android 9). Make sure you only use this code in Android 9 or greater.

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P){
    bindProcessToNetwork(); 
}
like image 174
Lance Avatar answered Sep 20 '22 23:09

Lance