Search code examples
androidandroid-download-manager

App crashes when enqueuing request to DownloadManager


I'm trying to make an app that download an iCal file using DownloadManager. After some research, I can't find a solution to my issue. Using the Android Studio debugger, I found out the app crashes when enqeuing the request. Here the error I get in the Android Monitor :

 java.lang.SecurityException: Permission Denial: writing com.android.providers.downloads.DownloadProvider uri content://downloads/my_downloads from pid=5082, uid=10208 requires android.permission.INTERNET, or grantUriPermission()

I don't understand why it requires the android.permission.INTERNET which is already given, as shown in my AndroidManifest below :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="galisson.esiea.pst3.smartwatch">

<application
    android:allowBackup="true"
    android:icon="@drawable/smartwatch"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


</application>

Here is my MainActivity :

public class MainActivity extends AppCompatActivity {

     EditText url;
     Button buttonAdd;

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

         url = (EditText) findViewById(R.id.editTextLink);
         buttonAdd = (Button) findViewById(R.id.buttonADD);

         buttonAdd.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 if(!url.getText().toString().isEmpty()) {
                     Uri iCalURI = Uri.parse(url.getText().toString());

                     DownloadData(iCalURI);

                 }
             }
         });


     }

     private void DownloadData(Uri p_uri) {

         DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
         DownloadManager.Request request = new DownloadManager.Request(p_uri);

         request.setDescription("iCal Calendar downloading");
         request.setTitle("iCal calendar");
         request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);                      //Restrict the types of networks over which this download may proceed.
         request.setAllowedOverRoaming(false);                                                                                               //Set whether this download may proceed over a roaming connection.
         request.allowScanningByMediaScanner();
         request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
         request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "iCal_tmp.ics");

         manager.enqueue(request);           //this is where it crashes

         return;
     }
  }

Is my problem with the permission or the request in itself?


Solution

  • First of grant permissions which you need.

    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG, "Permission is granted");
    
                writeFilesToSdCard();
                return true;
            } else {
    
                Log.v(TAG, "Permission is revoked");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                return false;
            }
        } else { //permission is automatically granted on sdk<23 upon installation
            writeFilesToSdCard();
            return true;
        }
    }
    

    Then request it with overrided method.

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "Permission: " + permissions[0] + "was " + grantResults[0]);
            //resume tasks needing this permission
        }
    }
    

    NOTE: Don't forget putting permissions in manifest outside of <application> tag.

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.myproject">
    
        <uses-permission android:name="android.permission.INTERNET" />    
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
        <application
            //
        </application>
    
    </manifest>