1

I have two fragments in a tab view layout. I am working with WebView() and DownloadManager() to download a file. My file is downloading perfectly but the downloaded file doesn't have the original file name. This is my problem. How do I get the original file name? I found some code here for this issue, but none of them helped me...

Here is my fragment where I am using the download manager:

public class Download extends Fragment {
    View v;
    WebView webView2;
    SwipeRefreshLayout mySwipeRefreshLayout;
    DownloadManager downloadManager;

    public String currentUrl = "";
    String myLink = "";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        v = inflater.inflate(R.layout.download, container, false);
        mySwipeRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.swiperefresh);
        webView2 = (WebView) v.findViewById(R.id.webView_download);

        int permissionCheck = ContextCompat.checkSelfPermission(getContext(),
            Manifest.permission.WRITE_EXTERNAL_STORAGE);

        webView2.setInitialScale(1);
        webView2.getSettings().setJavaScriptEnabled(true);
        webView2.getSettings().setLoadWithOverviewMode(true);
        webView2.getSettings().setUseWideViewPort(true);
        webView2.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
        webView2.setScrollbarFadingEnabled(false);
        webView2.setVerticalScrollBarEnabled(false);
        webView2.loadUrl(currentUrl);
        webView2.setWebViewClient(new WebViewClient());
        webView2.getSettings().setBuiltInZoomControls(true);
        webView2.getSettings().setUseWideViewPort(true);
        webView2.getSettings().setLoadWithOverviewMode(true);
        webView2.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        webView2.setOnTouchListener(new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return (event.getAction() == MotionEvent.ACTION_MOVE);
            }
        });

        if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
            Bundle bundle = getArguments();

            if (bundle != null) {
                String value = getArguments().getString("link");
                myLink = value;
                webView2.loadUrl(myLink);
            }

            webView2.setDownloadListener(new DownloadListener() {
                public void onDownloadStart(String url, String userAgent,
                                            String contentDisposition, String mimetype,
                                            long contentLength) {
                    Intent i = new Intent(Intent.ACTION_VIEW);
                    i.setData(Uri.parse(url));

                    downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
                    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
                    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Youtube_Video" + ".mp4");
                    request.allowScanningByMediaScanner();
                    Long reference = downloadManager.enqueue(request);

                    Toast.makeText(getContext(), "Downloading...", Toast.LENGTH_LONG).show();
                }
            });
        } else {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }

        return v;
    }
}
Nitol Neel
  • 11
  • 1
  • 5

2 Answers2

1

You are ignoring the contentDisposition parameter which you are receiving in your onDownloadStart() method — when the file is downloaded for example via a form submit or a POST request or sometimes via a GET method with redirect the Content-disposition header will usually contain the file name that you are looking for.

import android.webkit.URLUtil;

// ...

webView.setDownloadListener(new DownloadListener() {
    public void onDownloadStart(
        String url,
        String userAgent,
        String contentDisposition, // <<< HERE IS THE ANSWER <<<
        String mimetype,
        long contentLength) {

        String humanReadableFileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
        //     ^^^^^^^^^^^^^^^^^^^^^ the name you expect
    // ....


    });

Even though the contentDisposition will contain your original file name you will still need to use a BroadcastReceiver to get the actual content Uri:

    BroadcastReceiver onCompleteHandler = new BroadcastReceiver() {
        public void onReceive(Context ctx, Intent intent) {
            long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
            if (downloadId == downloadRef) {
                Log.d(TAG, "onReceive: " + intent);
                DownloadManager.Query query = new DownloadManager.Query();
                query.setFilterById(downloadId);
                Cursor cur = downloadManager.query(query);

                if (cur.moveToFirst()) {
                    int columnIndex = cur.getColumnIndex(DownloadManager.COLUMN_STATUS);
                    if (DownloadManager.STATUS_SUCCESSFUL == cur.getInt(columnIndex)) {
                        String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));

                        Uri uriDownloadedFile = Uri.parse(uriString);
                        // TODO: consume the uri
                }

            }
        }
    };
    registerReceiver(onCompleteHandler, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
ccpizza
  • 28,968
  • 18
  • 162
  • 169
0

HTTP doesn't include a separate filename generally. You can use the filename in the URL path, for example take everything after the last forward slash:

String filename = currentUrl.substring(currentUrl.lastIndexOf('/') + 1);

and then pass it into:

request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);

If there is a filename is in the headers however, a separate HEAD request would do the trick (see this answer).

tsn
  • 838
  • 9
  • 20
  • it doesn't work for me... downloaded file name like "watch?v=ZtgD9f0xPuU" is now...but i now exect name – Nitol Neel Jul 13 '17 at 18:17
  • If you know the exact name where does that information come from? – tsn Jul 13 '17 at 18:20
  • So in this situation the filename is the title of the video? If so, you'll want to request the title from YouTube before downloading the video (like [here](https://stackoverflow.com/a/15766363/783711)) – tsn Jul 13 '17 at 18:29
  • It looks like you want us to write some code for you. While many users are willing to produce code for a coder in distress, they usually only help when the poster has already tried to solve the problem on their own. A good way to demonstrate this effort is to include the code you've written so far, example input (if there is any), the expected output, and the output you actually get (console output, tracebacks, etc.). The more detail you provide, the more answers you are likely to receive. – tsn Jul 13 '17 at 19:07