Reports excel file download not working in traccar manager

steven6 years ago

Dear Anton,
I am studying traccar. My problem is that you can not download reports from the manager app. The server uses traccar demo server 5, and the manager is the source build, pure version in app.
The download works normally on PC and mobile web browser, but the download button on manager app does not respond.
How can i get reports from app?

Anton Tananaev6 years ago

Are you using Android or iOS? What version of Traccar Manager?

steven6 years ago

i'm use Android app (android Oreo, api 26), but i don't found version of Traccar Manager.. but manager source download recently. (2 weeks ago)

Anton Tananaev6 years ago

Looks like it's not supported yet. I have experimented with some code, but it doesn't seem to work for some reason:

    private String pendingDownloadUrl;

    private DownloadListener downloadListener = new DownloadListener() {
        @Override
        public void onDownloadStart(
                String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {

            if (url.startsWith("blob:")) {
                url = url.substring(url.indexOf("http"));
            }

            if (ContextCompat.checkSelfPermission(
                    getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                pendingDownloadUrl = url;
                ActivityCompat.requestPermissions(
                        getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSIONS_STORAGE);
            } else {
                downloadUrl(url);
            }
        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_PERMISSIONS_STORAGE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            downloadUrl(pendingDownloadUrl);
            pendingDownloadUrl = null;
        }
    }

    private void downloadUrl(String url) {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));

        String name = URLUtil.guessFileName(url, null, null);

        request.addRequestHeader("cookie", CookieManager.getInstance().getCookie(url));
        request.setDescription(getString(R.string.file_download));
        request.setTitle(name);
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, name);
        DownloadManager downloadManager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
        downloadManager.enqueue(request);

        Toast.makeText(getActivity(), R.string.file_download, Toast.LENGTH_LONG).show();
    }
steven6 years ago

Thanks your support.
I Fixed some code (REQUEST_PERMISSIONS_STORAGE in 110 for write permissions) and run it, looks like almost work.
(require permission, file_download string popup at toast)
but download has fail with 404 not found..

my logcat here.

08-23 09:50:47.283 29291-29303/? W/DownloadManager: Path appears to be invalid: /storage/emulated/0/Download/00b6d620-6016-449c-9adb-f0d17ba6b103.bin
08-23 09:50:47.382 29291-29921/? D/DownloadManager: [3228] Starting org.traccar.manager
08-23 09:50:48.122 29291-29921/? W/DownloadManager: [3228] Stop requested with status 404: Unhandled HTTP response: 404 Not Found
08-23 09:50:48.122 29291-29921/? D/DownloadManager: [3228] Finished with status 404
08-23 09:50:48.143 29291-29921/? V/DownloadManager: MIME Type = null
08-23 09:50:48.161 29291-29921/? D/DownloadManager: Send intent: mId:3228 status:404 mTitle:00b6d620-6016-449c-9adb-f0d17ba6b103.bin
08-23 09:50:48.174 29291-29921/? I/DownloadManager: Download 3228 finished with status 404
08-23 09:50:48.193 29291-29921/? I/DownloadManager: Notification Clear Download 1:org.traccar.manager

when i checked packet with wireshark, push export button and i see response have file packet.
in browser(PC or Mobile), they have 1 cycle(push export button(request) -> file data response, end)
but in webview, they have 2 cycle(first like browser, second is request blob url(maybe downloadmanger?) -> 404 not found response)

Anton Tananaev6 years ago

Here is the code we have in the web app:

        Ext.Ajax.request({
            url: requestUrl,
            method: 'GET',
            timeout: Traccar.Style.reportTimeout,
            params: requestParams,
            headers: {
                Accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            },
            binary: true,
            scope: this,
            callback: function (options, success, response) {
                var disposition, filename, type, blob, url, downloadUrl;
                if (success) {
                    disposition = response.getResponseHeader('Content-Disposition');
                    filename = disposition.slice(disposition.indexOf('=') + 1, disposition.length);
                    type = response.getResponseHeader('Content-Type');
                    blob = new Blob([response.responseBytes], {type: type});
                    if (typeof window.navigator.msSaveBlob !== 'undefined') {
                        // IE workaround
                        window.navigator.msSaveBlob(blob, filename);
                    } else {
                        url = window.URL || window.webkitURL;
                        downloadUrl = url.createObjectURL(blob);
                        if (filename) {
                            Ext.dom.Helper.append(Ext.getBody(), {
                                tag: 'a',
                                href: downloadUrl,
                                download: filename
                            }).click();
                        }
                        setTimeout(function () {
                            url.revokeObjectURL(downloadUrl);
                        }, 100);
                    }
                }
                this.reportProgress = false;
                this.updateButtons();
            }
        });

Basically we create a blob from server response. I suspect we need to handle blobs differently because it's basically local data.