title: Android studio download with downloadmanager and then open downloaded file
body: <p>(to make things clearer :) I am using <strong>WebView</strong>. The idea is that users can visit any page and download any file, the idea is to support as many basic features as i can to get closer feel to built in web browser.</p>
  
  <p>As the title says, i am trying to make my app <strong>download files and open them once theyre downloaded</strong>. There are some bullet points i want to mention :</p>
  
  <ul>
  <li>user should be able to <strong>download any kind of file</strong> (i guess its called mimeType), as they would in they default internet browser app</li>
  <li>since users download items from webview, it would only make sense if <strong>downloads would appear in downloads folder</strong></li>
  <li>would be awesome if every users device could decide on itself which app to use to open downloaded file, but, for example, my samsung s9 asks which app to use, thats not a bad option either</li>
  <li>i ran across some problems like sucessful download, but the file was empty/corrupted, the downlaoded file was missing in file browser even if app told me that the download is completed</li>
  </ul>
  
  <p>So i have been on not 2nd, not 3rd but even 5th page of google search results, so ive seen a lot, these are couple versions of my code so far, every single one of them are not working as i expected them in my dreams. </p>
  
  <p>Just to be clear, the code you are about to see is under webview setDownloadListener(new DownloadListener() ...</p>
  
  <p>So my latest version, without file opening after download :</p>
  
  <pre><code>public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
  
  //used to call a class to in previous code version to make some downloads
      //new DownloadTask(webview_base.this, url, mimeType);
  
              DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)).setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |
                      DownloadManager.Request.NETWORK_MOBILE);
              // in order for this if to run, you must use the android 3.2 to compile your app
              if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB) {
                  request.allowScanningByMediaScanner();
                  request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
              }
              request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, url.substring(url.lastIndexOf('/')));
  
              // get download service and enqueue file
              DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
              manager.enqueue(request);
  
          }
      });
  </code></pre>
  
  <p>the problem with ^ this version was that i was able to download files, but it downlaoded pages HTML instead of actual pdf or whatever i was aiming for, thats weird.</p>
  
  <p>previous version was a bit smoother, i was able to download files, and i used a dialog to offer to open a file. Everything worked fine, but documents were empty/corrupted and i got offered to open them with weird apps, for example, once i got asked to open pdf with my smartwatch app, but that mustve gone away since i edited a code time by time. The problem i landed here was that even after couple of ctrl+z i wasnt able to get my app back on feets - i was stuck at download screen and logcat shout at me that it couldnt fine a download directory. at that point i got mad and started the version you can see above. Anyway, here is the whole class :</p>
  
  <pre><code>package com.example.viaapp_v2;
  import android.app.AlertDialog;
  import android.app.ProgressDialog;
  import android.content.ActivityNotFoundException;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.Intent;
  import android.net.Uri;
  import android.os.AsyncTask;
  import android.os.Environment;
  import android.os.Handler;
  import android.util.Log;
  import android.view.ContextThemeWrapper;
  import android.widget.Toast;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.InputStream;
  import java.net.HttpURLConnection;
  import java.net.URL;
  
  import androidx.core.content.FileProvider;
  
  public class DownloadTask extends FileProvider {
      private static final String TAG = "Download Task";
      private Context context;
      String mimeType;
      private String downloadUrl = "", downloadFileName = "";
      private ProgressDialog progressDialog;
  public DownloadTask() {
      //required empty constructor
  }
  
  public DownloadTask(Context context, String downloadUrl, String mime) {
      this.context = context;
      this.downloadUrl = downloadUrl;
      this.mimeType = mime;
      //Create file name by picking download file name from URL
      downloadFileName = downloadUrl.substring(downloadUrl.lastIndexOf('/'));
  
  
      //Start Downloading Task
      new DownloadingTask().execute();
  }
  
  private class DownloadingTask extends AsyncTask&lt;Void, Void, Void&gt; {
  
      File apkStorage = null;
      File outputFile = null;
  
      @Override
      protected void onPreExecute() {
          super.onPreExecute();
          progressDialog = new ProgressDialog(context);
          progressDialog.setMessage("Downloading...");
          progressDialog.setCancelable(false);
          progressDialog.show();
      }
  
      @Override
      protected void onPostExecute(Void result) {
          try {
              if (outputFile != null) {
                  progressDialog.dismiss();
                  final ContextThemeWrapper ctw = new ContextThemeWrapper( context, R.style.Theme_AppCompat_Light_Dialog);
                  final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ctw);
                  alertDialogBuilder.setTitle("Document  ");
                  alertDialogBuilder.setMessage(downloadFileName+" Downloaded Successfully ");
                  alertDialogBuilder.setCancelable(false);
                  alertDialogBuilder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int id) {
  
                      }
                  });
  
                  alertDialogBuilder.setNegativeButton("Open file",new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int id) {
  
                          try {
                              File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()
                                      + downloadFileName);//name here is the name of any string you want to pass to the method
                              if (!file.isDirectory())
                                  file.mkdir();
                              Intent testIntent = new Intent();
                              testIntent.setType(mimeType);
                              testIntent.setAction(Intent.ACTION_VIEW);
                              Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
                              testIntent.setDataAndType(uri, mimeType);
                              ctw.startActivity(testIntent);
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                      }
                  });
                  alertDialogBuilder.show();
              } else {
  
                  new Handler().postDelayed(new Runnable() {
                      @Override
                      public void run() {
  
                      }
                  }, 3000);
  
                  Log.e(TAG, "Download Failed");
  
              }
          } catch (Exception e) {
              e.printStackTrace();
  
              //Change button text if exception occurs
  
              new Handler().postDelayed(new Runnable() {
                  @Override
                  public void run() {
  
                  }
              }, 3000);
              Log.e(TAG, "Download Failed with Exception - " + e.getLocalizedMessage());
  
          }
  
  
          super.onPostExecute(result);
      }
  
      @Override
      protected Void doInBackground(Void... arg0) {
          try {
              URL url = new URL(downloadUrl);//Create Download URl
              HttpURLConnection c = (HttpURLConnection) url.openConnection();//Open Url Connection
              c.setRequestMethod("GET");//Set Request Method to "GET" since we are grtting data
              c.connect();//connect the URL Connection
  
              //If Connection response is not OK then show Logs
              if (c.getResponseCode() != HttpURLConnection.HTTP_OK) {
                  Log.e(TAG, "Server returned HTTP " + c.getResponseCode()
                          + " " + c.getResponseMessage());
  
              }
  
  
              //Get File if SD card is present
              if (new CheckForSDCard().isSDCardPresent()) {
  
                  apkStorage = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
              } else
                  Toast.makeText(context, "Oops!! There is no SD Card.", Toast.LENGTH_SHORT).show();
  
              //If File is not present create directory
              if (!apkStorage.exists()) {
                  apkStorage.mkdir();
                  Log.e(TAG, "Directory Created.");
              }
  
              outputFile = new File(apkStorage, downloadFileName);//Create Output file in Main File
  
              //Create New File if not present
              if (!outputFile.exists()) {
                  outputFile.createNewFile();
                  Log.e(TAG, "File Created");
              }
  
              FileOutputStream fos = new FileOutputStream(outputFile);//Get OutputStream for NewFile Location
  
              InputStream is = c.getInputStream();//Get InputStream for connection
  
              byte[] buffer = new byte[1024];//Set buffer type
              int len1 = 0;//init length
              while ((len1 = is.read(buffer)) != -1) {
                  fos.write(buffer, 0, len1);//Write new file
              }
  
              //Close all connection after doing task
              fos.close();
              is.close();
  
          } catch (Exception e) {
  
              //Read exception if something went wrong
              e.printStackTrace();
              outputFile = null;
              Log.e(TAG, "Download Error Exception " + e.getMessage());
          }
  
          return null;
      }
  }
  
  private class CheckForSDCard {
      //Check If SD Card is present or not method
      boolean isSDCardPresent() {
          return Environment.getExternalStorageState().equals(
                  Environment.MEDIA_MOUNTED);
      }
  }
  }
  </code></pre>
  
  <p>Looking for my manifest file ? Well here it goes .. ive put in some support for file upload, file download, internet acces, ect</p>
  
  <pre><code>&lt;uses-permission android:name="android.permission.INTERNET" /&gt;
  &lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/&gt;
  &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
  &lt;uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&gt;
  &lt;uses-permission android:name="android.permission.RECORD_AUDIO" /&gt;
  &lt;uses-feature android:name="android.hardware.camera"/&gt;
  &lt;uses-permission android:name="android.permission.CAMERA"/&gt;
  </code></pre>
  
  <p>i even tried to put some provider stuff in application</p>
  
  <pre><code>&lt;provider
          android:name=".DownloadTask"
          android:authorities="${applicationId}.provider"
          android:exported="false"
          android:grantUriPermissions="true"&gt;
          &lt;meta-data
              android:name="android.support.FILE_PROVIDER_PATHS"
              android:resource="@xml/provider_paths"/&gt;
      &lt;/provider&gt;
  </code></pre>
  
  <p>But deep inside i had no idea what to put in provider path file </p>
  
  <pre><code>&lt;paths&gt;&lt;external-path name="external_files" path="."/&gt;&lt;/paths&gt;
  </code></pre>
  
  <p>Sorry that this text is so long. Im just desperate and almost done with my project, but i have to seek for help somewhere to keep going. I hope ive explained my problem enough and provided enough code, would be happy to know which code is better / more possible ( make a class or write everything down right under listener ).</p>
  
  <p>--- EDIT ---</p>
  
  <p>So.. i tried to run my old version of code, which is that long block of code above, class file "DownloadTask.java", which is called by constructor, passing utl, mimetype and context. You can see the line commented in the first block of code in this post, 3rd line. Here is what happened : i visited a page, clicked on a link to download pdf file, but then i got stuck on dialog that shows "downloading.." while logcat said this :</p>
  
  <pre><code>D/ViewRootImpl@19478bd[webview_base]: MSG_RESIZED: frame=Rect(18, 617 - 701, 821) ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
  D/ViewRootImpl@c47c382[webview_base]: Relayout returned: old=[0,0][720,1480] new=[0,0][720,1480] result=0x1 surface={valid=true 484837122048} changed=false
  I/ample.viaapp_v: Compiler allocated 4MB to compile void android.widget.TextView.&lt;init&gt;(android.content.Context, android.util.AttributeSet, int, int)
  I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
  I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
  W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Download/Datu%20p%C4%81rraides%20t%C4%ABkli-III_LV.pdf (Is a directory)
          at java.io.FileOutputStream.open0(Native Method)
          at java.io.FileOutputStream.open(FileOutputStream.java:308)
          at java.io.FileOutputStream.&lt;init&gt;(FileOutputStream.java:238)
          at java.io.FileOutputStream.&lt;init&gt;(FileOutputStream.java:180)
          at com.example.viaapp_v2.DownloadTask$DownloadingTask.doInBackground(DownloadTask.java:173)
          at com.example.viaapp_v2.DownloadTask$DownloadingTask.doInBackground(DownloadTask.java:54)
  W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:333)
          at java.util.concurrent.FutureTask.run(FutureTask.java:266)
          at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
          at java.lang.Thread.run(Thread.java:764)
  E/Download Task: Download Error Exception /storage/emulated/0/Download/Datu%20p%C4%81rraides%20t%C4%ABkli-III_LV.pdf (Is a directory)
  E/Download Task: Download Failed
  D/ViewRootImpl@19478bd[webview_base]: MSG_WINDOW_FOCUS_CHANGED 1 1
  </code></pre>
  
  <p>And yes, as you can see, the file name contais accented letters, thats why its so weird, 99% of users which are willing to use the app, will work around content which uses accented letters so im wondering mayeb i should replace filenames without all these letters like "āēīģčķ" to "aeigck".</p>