| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.download; | 5 package org.chromium.chrome.browser.download; |
| 6 | 6 |
| 7 import android.Manifest.permission; | 7 import android.Manifest.permission; |
| 8 import android.app.Activity; | 8 import android.app.Activity; |
| 9 import android.app.DownloadManager; | 9 import android.app.DownloadManager; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| 11 import android.content.DialogInterface; | 11 import android.content.DialogInterface; |
| 12 import android.content.Intent; | 12 import android.content.Intent; |
| 13 import android.content.pm.PackageManager; | 13 import android.content.pm.PackageManager; |
| 14 import android.net.Uri; | 14 import android.net.Uri; |
| 15 import android.os.AsyncTask; | 15 import android.os.AsyncTask; |
| 16 import android.os.Environment; | 16 import android.os.Environment; |
| 17 import android.support.v7.app.AlertDialog; | 17 import android.support.v7.app.AlertDialog; |
| 18 import android.text.TextUtils; | 18 import android.text.TextUtils; |
| 19 import android.util.Pair; | 19 import android.util.Pair; |
| 20 import android.view.View; | 20 import android.view.View; |
| 21 import android.webkit.MimeTypeMap; | 21 import android.webkit.MimeTypeMap; |
| 22 import android.webkit.URLUtil; | |
| 23 import android.widget.TextView; | 22 import android.widget.TextView; |
| 24 | 23 |
| 25 import org.chromium.base.Log; | 24 import org.chromium.base.Log; |
| 26 import org.chromium.base.ThreadUtils; | 25 import org.chromium.base.ThreadUtils; |
| 27 import org.chromium.base.VisibleForTesting; | |
| 28 import org.chromium.base.annotations.CalledByNative; | 26 import org.chromium.base.annotations.CalledByNative; |
| 29 import org.chromium.chrome.R; | 27 import org.chromium.chrome.R; |
| 30 import org.chromium.chrome.browser.infobar.InfoBarIdentifier; | 28 import org.chromium.chrome.browser.infobar.InfoBarIdentifier; |
| 31 import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; | 29 import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; |
| 32 import org.chromium.chrome.browser.tab.EmptyTabObserver; | 30 import org.chromium.chrome.browser.tab.EmptyTabObserver; |
| 33 import org.chromium.chrome.browser.tab.Tab; | 31 import org.chromium.chrome.browser.tab.Tab; |
| 34 import org.chromium.chrome.browser.tabmodel.TabModelSelector; | 32 import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
| 35 import org.chromium.content.browser.ContentViewDownloadDelegate; | 33 import org.chromium.content.browser.ContentViewDownloadDelegate; |
| 36 import org.chromium.content.browser.DownloadController; | 34 import org.chromium.content.browser.DownloadController; |
| 37 import org.chromium.content.browser.DownloadInfo; | 35 import org.chromium.content.browser.DownloadInfo; |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 // If the intent is resolved to ourselves, we don't want to attempt
to load the url | 168 // If the intent is resolved to ourselves, we don't want to attempt
to load the url |
| 171 // only to try and download it again. | 169 // only to try and download it again. |
| 172 if (DownloadManagerService.openIntent(mContext, intent, false)) { | 170 if (DownloadManagerService.openIntent(mContext, intent, false)) { |
| 173 return; | 171 return; |
| 174 } | 172 } |
| 175 } | 173 } |
| 176 onDownloadStartNoStream(downloadInfo); | 174 onDownloadStartNoStream(downloadInfo); |
| 177 } | 175 } |
| 178 | 176 |
| 179 /** | 177 /** |
| 180 * Decide the file name of the final download. The file extension is derived | |
| 181 * from the MIME type. | |
| 182 * @param url The full URL to the content that should be downloaded. | |
| 183 * @param mimeType The MIME type of the content reported by the server. | |
| 184 * @param contentDisposition Content-Disposition HTTP header, if present. | |
| 185 * @return The best guess of the file name for the downloaded object. | |
| 186 */ | |
| 187 @VisibleForTesting | |
| 188 public static String fileName(String url, String mimeType, String contentDis
position) { | |
| 189 // URLUtil#guessFileName will prefer the MIME type extension over | |
| 190 // the file extension only if the latter is of a known MIME type. | |
| 191 // Therefore for things like "file.php" with Content-Type PDF, it will | |
| 192 // still generate file names like "file.php" instead of "file.pdf". | |
| 193 // If that's the case, rebuild the file extension from the MIME type. | |
| 194 String fileName = URLUtil.guessFileName(url, contentDisposition, mimeTyp
e); | |
| 195 int dotIndex = fileName.lastIndexOf('.'); | |
| 196 if (mimeType != null | |
| 197 && !mimeType.isEmpty() | |
| 198 && dotIndex > 1 // at least one char before the '.' | |
| 199 && dotIndex < fileName.length()) { // '.' should not be the last
char | |
| 200 MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); | |
| 201 | |
| 202 String fileRoot = fileName.substring(0, dotIndex); | |
| 203 String fileExtension = fileName.substring(dotIndex + 1); | |
| 204 String fileExtensionMimeType = | |
| 205 mimeTypeMap.getMimeTypeFromExtension(fileExtension); | |
| 206 | |
| 207 // If the file extension's official MIME type and {@code mimeType} | |
| 208 // are the same, simply use the file extension. | |
| 209 // If not, extension derived from {@code mimeType} is preferred. | |
| 210 if (mimeType.equals(fileExtensionMimeType)) { | |
| 211 fileName = fileRoot + "." + fileExtension; | |
| 212 } else { | |
| 213 String mimeExtension = | |
| 214 mimeTypeMap.getExtensionFromMimeType(mimeType); | |
| 215 | |
| 216 if (mimeExtension != null && !mimeExtension.equals(fileExtension
)) { | |
| 217 fileName = fileRoot + "." + mimeExtension; | |
| 218 } | |
| 219 } | |
| 220 } | |
| 221 return fileName; | |
| 222 } | |
| 223 | |
| 224 /** | |
| 225 * Notify the host application a download should be done, even if there is a | 178 * Notify the host application a download should be done, even if there is a |
| 226 * streaming viewer available for this type. | 179 * streaming viewer available for this type. |
| 227 * | 180 * |
| 228 * @param downloadInfo Information about the download. | 181 * @param downloadInfo Information about the download. |
| 229 */ | 182 */ |
| 230 protected void onDownloadStartNoStream(final DownloadInfo downloadInfo) { | 183 protected void onDownloadStartNoStream(final DownloadInfo downloadInfo) { |
| 184 final String fileName = downloadInfo.getFileName(); |
| 185 assert !TextUtils.isEmpty(fileName); |
| 231 final String newMimeType = remapGenericMimeType( | 186 final String newMimeType = remapGenericMimeType( |
| 232 downloadInfo.getMimeType(), | 187 downloadInfo.getMimeType(), |
| 233 downloadInfo.getUrl(), | 188 downloadInfo.getUrl(), |
| 234 downloadInfo.getFileName()); | 189 fileName); |
| 235 final String fileName = TextUtils.isEmpty(downloadInfo.getFileName()) | |
| 236 ? fileName(downloadInfo.getUrl(), newMimeType, downloadInfo.getC
ontentDisposition()) | |
| 237 : downloadInfo.getFileName(); | |
| 238 new AsyncTask<Void, Void, Object[]>() { | 190 new AsyncTask<Void, Void, Object[]>() { |
| 239 @Override | 191 @Override |
| 240 protected Object[] doInBackground(Void... params) { | 192 protected Object[] doInBackground(Void... params) { |
| 241 // Check to see if we have an SDCard. | 193 // Check to see if we have an SDCard. |
| 242 String status = Environment.getExternalStorageState(); | 194 String status = Environment.getExternalStorageState(); |
| 243 Pair<String, String> result = getDownloadDirectoryNameAndFullPat
h(); | 195 Pair<String, String> result = getDownloadDirectoryNameAndFullPat
h(); |
| 244 String dirName = result.first; | 196 String dirName = result.first; |
| 245 String fullDirPath = result.second; | 197 String fullDirPath = result.second; |
| 246 boolean fileExists = doesFileAlreadyExists(fullDirPath, fileName
); | 198 boolean fileExists = doesFileAlreadyExists(fullDirPath, fileName
); |
| 247 | 199 |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 private static native String nativeGetDownloadWarningText(String filename); | 631 private static native String nativeGetDownloadWarningText(String filename); |
| 680 private static native boolean nativeIsDownloadDangerous(String filename); | 632 private static native boolean nativeIsDownloadDangerous(String filename); |
| 681 private static native void nativeDangerousDownloadValidated( | 633 private static native void nativeDangerousDownloadValidated( |
| 682 Object tab, int downloadId, boolean accept); | 634 Object tab, int downloadId, boolean accept); |
| 683 private static native void nativeLaunchDownloadOverwriteInfoBar(ChromeDownlo
adDelegate delegate, | 635 private static native void nativeLaunchDownloadOverwriteInfoBar(ChromeDownlo
adDelegate delegate, |
| 684 Tab tab, DownloadInfo downloadInfo, String fileName, String dirName, | 636 Tab tab, DownloadInfo downloadInfo, String fileName, String dirName, |
| 685 String dirFullPath); | 637 String dirFullPath); |
| 686 private static native void nativeLaunchPermissionUpdateInfoBar( | 638 private static native void nativeLaunchPermissionUpdateInfoBar( |
| 687 Tab tab, String permission, long callbackId); | 639 Tab tab, String permission, long callbackId); |
| 688 } | 640 } |
| OLD | NEW |