summaryrefslogtreecommitdiffstats
path: root/content/public/android/java/src/org/chromium/content/browser/DownloadController.java
blob: 63a5eb747ff48e552959d2b1e7fde3eb901859f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.content.browser;

import android.Manifest.permission;
import android.content.pm.PackageManager;

import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.ui.base.WindowAndroid.PermissionCallback;

/**
 * Java counterpart of android DownloadController.
 *
 * Its a singleton class instantiated by the C++ DownloadController.
 */
@JNINamespace("content")
public class DownloadController {
    private static final String LOGTAG = "DownloadController";
    private static final DownloadController sInstance = new DownloadController();

    /**
     * Class for notifying the application that download has completed.
     */
    public interface DownloadNotificationService {
        /**
         * Notify the host application that a download is finished.
         * @param downloadInfo Information about the completed download.
         */
        void onDownloadCompleted(final DownloadInfo downloadInfo);

        /**
         * Notify the host application that a download is in progress.
         * @param downloadInfo Information about the in-progress download.
         */
        void onDownloadUpdated(final DownloadInfo downloadInfo);

        /**
         * Notify the host application that a download is cancelled.
         * @param downloadId Id of the download.
         */
        void onDownloadCancelled(final DownloadInfo downloadInfo);

        /**
         * Notify the host application that a download is interrupted.
         * @param downloadInfo Information about the completed download.
         * @param isAutoResumable Download can be auto resumed when network becomes available.
         */
        void onDownloadInterrupted(final DownloadInfo downloadInfo, boolean isAutoResumable);
    }

    private static DownloadNotificationService sDownloadNotificationService;

    @CalledByNative
    public static DownloadController getInstance() {
        return sInstance;
    }

    private DownloadController() {
        nativeInit();
    }

    private static ContentViewDownloadDelegate downloadDelegateFromView(ContentViewCore view) {
        return view.getDownloadDelegate();
    }

    public static void setDownloadNotificationService(DownloadNotificationService service) {
        sDownloadNotificationService = service;
    }

    /**
     * Notifies the download delegate of a new GET download and passes all the information
     * needed to download the file.
     *
     * The download delegate is expected to handle the download.
     */
    @CalledByNative
    private void newHttpGetDownload(ContentViewCore view, String url,
            String userAgent, String contentDisposition, String mimeType,
            String cookie, String referer, boolean hasUserGesture,
            String filename, long contentLength) {
        ContentViewDownloadDelegate downloadDelegate = downloadDelegateFromView(view);

        if (downloadDelegate == null) return;
        DownloadInfo downloadInfo = new DownloadInfo.Builder()
                .setUrl(url)
                .setUserAgent(userAgent)
                .setContentDisposition(contentDisposition)
                .setMimeType(mimeType)
                .setCookie(cookie)
                .setReferer(referer)
                .setHasUserGesture(hasUserGesture)
                .setFileName(filename)
                .setContentLength(contentLength)
                .setIsGETRequest(true)
                .build();
        downloadDelegate.requestHttpGetDownload(downloadInfo);
    }

    /**
     * Notifies the download delegate that a new download has started. This can
     * be either a POST download or a GET download with authentication.
     * @param view ContentViewCore associated with the download item.
     * @param filename File name of the downloaded file.
     * @param mimeType Mime of the downloaded item.
     */
    @CalledByNative
    private void onDownloadStarted(ContentViewCore view, String filename, String mimeType) {
        ContentViewDownloadDelegate downloadDelegate = downloadDelegateFromView(view);

        if (downloadDelegate != null) {
            downloadDelegate.onDownloadStarted(filename, mimeType);
        }
    }

    /**
     * Notifies the download delegate that a download completed and passes along info about the
     * download. This can be either a POST download or a GET download with authentication.
     */
    @CalledByNative
    private void onDownloadCompleted(String url, String mimeType, String filename, String path,
            long contentLength, int downloadId, String originalUrl, String refererUrl,
            boolean hasUserGesture) {
        if (sDownloadNotificationService == null) return;
        DownloadInfo downloadInfo = new DownloadInfo.Builder()
                .setUrl(url)
                .setMimeType(mimeType)
                .setFileName(filename)
                .setFilePath(path)
                .setContentLength(contentLength)
                .setDescription(filename)
                .setDownloadId(downloadId)
                .setHasDownloadId(true)
                .setOriginalUrl(originalUrl)
                .setReferer(refererUrl)
                .setHasUserGesture(hasUserGesture)
                .build();
        sDownloadNotificationService.onDownloadCompleted(downloadInfo);
    }

    /**
     * Notifies the download delegate that a download completed and passes along info about the
     * download. This can be either a POST download or a GET download with authentication.
     */
    @CalledByNative
    private void onDownloadInterrupted(String url, String mimeType, String filename, String path,
            long contentLength, int downloadId, boolean isResumable, boolean isAutoResumable) {
        if (sDownloadNotificationService == null) return;
        DownloadInfo downloadInfo = new DownloadInfo.Builder()
                .setUrl(url)
                .setMimeType(mimeType)
                .setFileName(filename)
                .setFilePath(path)
                .setContentLength(contentLength)
                .setDescription(filename)
                .setDownloadId(downloadId)
                .setHasDownloadId(true)
                .setIsResumable(isResumable)
                .build();
        sDownloadNotificationService.onDownloadInterrupted(downloadInfo, isAutoResumable);
    }

    /**
     * Called when a download was cancelled.
     * @param downloadId Id of the download item.
     */
    @CalledByNative
    private void onDownloadCancelled(int downloadId) {
        if (sDownloadNotificationService == null) return;
        DownloadInfo downloadInfo = new DownloadInfo.Builder()
                .setDownloadId(downloadId)
                .setHasDownloadId(true)
                .build();
        sDownloadNotificationService.onDownloadCancelled(downloadInfo);
    }

    /**
     * Notifies the download delegate about progress of a download. Downloads that use Chrome
     * network stack use custom notification to display the progress of downloads.
     */
    @CalledByNative
    private void onDownloadUpdated(String url, String mimeType, String filename,
            String path, long contentLength, int downloadId, int percentCompleted,
            long timeRemainingInMs, boolean hasUserGesture, boolean isPaused, boolean isResumable) {
        if (sDownloadNotificationService == null) return;
        DownloadInfo downloadInfo = new DownloadInfo.Builder()
                .setUrl(url)
                .setMimeType(mimeType)
                .setFileName(filename)
                .setFilePath(path)
                .setContentLength(contentLength)
                .setDescription(filename)
                .setDownloadId(downloadId)
                .setHasDownloadId(true)
                .setPercentCompleted(percentCompleted)
                .setTimeRemainingInMillis(timeRemainingInMs)
                .setHasUserGesture(hasUserGesture)
                .setIsPaused(isPaused)
                .setIsResumable(isResumable)
                .build();
        sDownloadNotificationService.onDownloadUpdated(downloadInfo);
    }

    /**
     * Notifies the download delegate that a dangerous download started.
     */
    @CalledByNative
    private void onDangerousDownload(ContentViewCore view, String filename,
            int downloadId) {
        ContentViewDownloadDelegate downloadDelegate = downloadDelegateFromView(view);
        if (downloadDelegate != null) {
            downloadDelegate.onDangerousDownload(filename, downloadId);
        }
    }

    /**
     * Returns whether file access is allowed.
     *
     * @param view The ContentViewCore to access file system.
     * @return true if allowed, or false otherwise.
     */
    @CalledByNative
    private boolean hasFileAccess(ContentViewCore view) {
        return view.getWindowAndroid().hasPermission(permission.WRITE_EXTERNAL_STORAGE);
    }

    /**
     * Called to prompt user with the file access permission.
     *
     * @param view The ContentViewCore to access file system.
     * @param callbackId The native callback function pointer.
     */
    @CalledByNative
    private void requestFileAccess(final ContentViewCore view, final long callbackId) {
        ContentViewDownloadDelegate downloadDelegate = downloadDelegateFromView(view);
        if (downloadDelegate != null) {
            downloadDelegate.requestFileAccess(callbackId);
        } else {
            PermissionCallback permissionCallback = new PermissionCallback() {
                @Override
                public void onRequestPermissionsResult(String[] permissions, int[] grantResults) {
                    onRequestFileAccessResult(callbackId, grantResults.length > 0
                            && grantResults[0] == PackageManager.PERMISSION_GRANTED);
                }
            };
            view.getWindowAndroid().requestPermissions(
                    new String[] {android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    permissionCallback);
        }
    }

    /**
     * Notify the results of a file access request.
     * @param callbackId The ID of the callback.
     * @param granted Whether access was granted.
     */
    public void onRequestFileAccessResult(long callbackId, boolean granted) {
        nativeOnRequestFileAccessResult(callbackId, granted);
    }

    // native methods
    private native void nativeInit();
    private native void nativeOnRequestFileAccessResult(long callbackId, boolean granted);
}