diff options
-rw-r--r-- | AndroidManifest.xml | 12 | ||||
-rw-r--r-- | res/layout/download_settings.xml | 203 | ||||
-rw-r--r-- | res/values-zh-rCN/strings.xml | 27 | ||||
-rw-r--r-- | res/values/strings.xml | 29 | ||||
-rw-r--r-- | res/xml/download_settings_preferences.xml | 42 | ||||
-rw-r--r-- | src/com/android/browser/BrowserSettings.java | 5 | ||||
-rw-r--r-- | src/com/android/browser/Controller.java | 6 | ||||
-rw-r--r-- | src/com/android/browser/DownloadHandler.java | 424 | ||||
-rw-r--r-- | src/com/android/browser/DownloadSettings.java | 312 | ||||
-rw-r--r-- | src/com/android/browser/FetchUrlMimeType.java | 203 | ||||
-rw-r--r-- | src/com/android/browser/PreferenceKeys.java | 3 | ||||
-rw-r--r-- | src/com/android/browser/preferences/AdvancedPreferencesFragment.java | 65 |
12 files changed, 1239 insertions, 92 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 14ec59e5..8c88f437 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -36,6 +36,7 @@ <uses-permission android:name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" /> <uses-permission android:name="android.permission.SET_WALLPAPER" /> <uses-permission android:name="android.permission.WAKE_LOCK"/> + <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> @@ -198,6 +199,17 @@ </intent-filter> </activity> + <activity android:name="DownloadSettings" android:label="@string/download_settings_title" + android:theme="@style/DialogWhenLarge" + android:launchMode="singleTask" + android:configChanges="orientation|keyboardHidden|screenSize" + android:windowSoftInputMode="adjustResize"> + <intent-filter> + <action android:name="android.intent.action.BROWSERDOWNLOAD" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <activity android:name="ComboViewActivity"> </activity> diff --git a/res/layout/download_settings.xml b/res/layout/download_settings.xml new file mode 100644 index 00000000..ad473630 --- /dev/null +++ b/res/layout/download_settings.xml @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2013, The Linux Foundation. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:divider="?android:attr/dividerHorizontal" + android:orientation="vertical" + android:showDividers="middle" > + <LinearLayout android:id="@+id/title_holder" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingLeft="5dip" + android:paddingRight="5dip" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + > + <TextView android:id="@+id/download_settings_title" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:gravity="center_vertical" + android:drawableLeft="@drawable/ic_bookmark_on_holo_dark" + android:text="@string/download_settings_title" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + </LinearLayout> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1" > + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent" > + + <TableLayout + android:id="@+id/download_table_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="20dip" + android:paddingRight="20dip" + android:paddingTop="10dip" + android:shrinkColumns="1" + android:stretchColumns="1" > + + <TableRow android:layout_marginBottom="10dip" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:text="@string/download_edit_filename_label" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </TextView> + + <EditText + android:id="@+id/download_filename_edit" + android:layout_width="260dip" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:inputType="textCapSentences" + android:selectAllOnFocus="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </EditText> + </TableRow> + + <TableRow + android:layout_marginBottom="10dip" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:text="@string/download_filepath_label" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </TextView> + + <EditText + android:id="@+id/download_filepath_selected" + android:layout_width="260dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:editable="false" + android:ellipsize="end" + android:focusableInTouchMode="false" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="@android:color/holo_blue_light" + android:textSize="18sp" > + </EditText> + </TableRow> + + <TableRow + android:layout_marginBottom="10dip" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/download_filesize" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </TextView> + <TextView + android:id="@+id/download_estimate_size_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/download_filesize" + android:paddingLeft="10dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </TextView> + </TableRow> + + <TableRow + android:layout_marginBottom="10dip" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:text="@string/download_timeneeded" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </TextView> + <TextView + android:id="@+id/download_estimate_time_content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:paddingLeft="10dip" + android:text="@string/download_timeneeded" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="18sp" > + </TextView> + </TableRow> + </TableLayout> + </ScrollView> + </FrameLayout> + + <LinearLayout + style="?android:attr/buttonBarStyle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + + <Button + android:id="@+id/download_cancle" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="right" + android:layout_weight="1" + android:maxLines="1" + android:text="@string/download_cancel" /> + + <Button + android:id="@+id/download_start" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:layout_weight="1" + android:maxLines="1" + android:text="@string/download_start" /> + </LinearLayout> + +</LinearLayout> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 84f117c5..e3df6d7e 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -432,4 +432,31 @@ <string name="save_to_bookmarks_title">保存书签</string> <string name="duplicated_folder_warning">该文件夹已经存在</string> <string name="overwrite_bookmark_msg">该书签的标签或者地址已经存在,是否覆盖?</string> + + <!-- Add for download save path setting Feature --> + <string name="invalid_path">"无效路径!"</string> + <string name="path_wrong">"路径错误"</string> + <string name="pref_download_title">下载路径设置</string> + <string name="pref_download_path_setting_screen_title">自定义下载路径</string> + <string name="download_start">确定</string> + <string name="download_cancel">取消</string> + <string name="download_timeneeded">时间</string> + <string name="download_filesize">大小</string> + <string name="download_filepath_label">路径</string> + <string name="download_edit_filename_label">名称</string> + <string name="download_default_path">/Download</string> + <string name="download_no_enough_memory">存储空间不足</string> + <string name="download_settings_title">下载设置</string> + <string name="save_page_needs_title">文件名称不能为空!</string> + <string name="filename_empty_title">文件名为空</string> + <string name="filename_empty_msg">文件名不能为空,请重新输入!</string> + <string name="unknow_length">未知</string> + <string name="download_file_exist_msg">文件已经存在,请重新输入文件名!</string> + <string name="download_file_exist">文件已经存在</string> + <string name ="time_min">分钟</string> + <string name="download_path_phone_stroage_label">/内置存储器</string> + <string name="download_path_sd_card_label">/SD卡</string> + <string name="download_path_unavailable_dlg_title">浏览器的下载路径不可达</string> + <string name="download_path_unavailable_dlg_msg">请重新设置浏览器的下载路径</string> + <string name="activity_not_found">没有找到处理 Intent <xliff:g id="NOACTIVITY">%s</xliff:g> 的Activity.</string> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index cf8d0ab7..2aa0ddb5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1046,4 +1046,33 @@ <string name="save_to_bookmarks_title">Save to Bookmarks</string> <string name="duplicated_folder_warning">The folder has already exists</string> <string name="overwrite_bookmark_msg">This bookmark\'s name or address already exists, overwrite it?</string> + + <!-- Add for download save path setting Feature --> + <string name="invalid_path">"Path is invalid!"</string> + <string name="path_wrong">"Wrong Path"</string> + <string name="pref_download_title">Download Path Settings</string> + <string name="pref_download_path_setting_screen_title">Custom Download Path</string> + <string name="download_start">OK</string> + <string name="download_cancel">Cancel</string> + <string name="download_timeneeded">Time</string> + <string name="download_filesize">Size</string> + <string name="download_filepath_label">Path</string> + <string name="download_edit_filename_label">Name</string> + <string name="download_default_path">default</string> + <string name="default_savepath_name">/Download</string> + <string name="download_no_enough_memory">Download no enough memory</string> + <string name="download_settings_title">Download Settings</string> + <string name="save_page_needs_title">Download File Name is Empty!</string> + <string name="filename_empty_title">Download File Name is Null</string> + <string name="filename_empty_msg">Download File Name Can not Be Null!Please Enter a Valid File Name!</string> + <string name="download_file_setting">Download File Settings</string> + <string name="unknow_length">Unknow</string> + <string name="download_file_exist_msg">This File is Already Exist,Please Enter a New File Name!</string> + <string name="download_file_exist">File Exist</string> + <string name ="time_min">min</string> + <string name="download_path_phone_stroage_label">/Phone Stroage</string> + <string name="download_path_sd_card_label">/SD card</string> + <string name="download_path_unavailable_dlg_title">Download Directory Unavailable</string> + <string name="download_path_unavailable_dlg_msg">Please modify the Download Directory of Browser</string> + <string name="activity_not_found">Activity Not Found to Handle Intent <xliff:g id="NOACTIVITY">%s</xliff:g>.</string> </resources> diff --git a/res/xml/download_settings_preferences.xml b/res/xml/download_settings_preferences.xml new file mode 100644 index 00000000..0cd99a98 --- /dev/null +++ b/res/xml/download_settings_preferences.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2013, The Linux Foundation. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android" > + + <PreferenceCategory + android:title="@string/pref_download_title" + android:key="download_path_setting_category"> + <PreferenceScreen + android:key="download_path_setting_screen" + android:title="@string/pref_download_path_setting_screen_title"/> + + </PreferenceCategory> + +</PreferenceScreen> diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java index 0b415be3..b6ccfe5f 100644 --- a/src/com/android/browser/BrowserSettings.java +++ b/src/com/android/browser/BrowserSettings.java @@ -713,6 +713,11 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, } } + public String getDownloadPath() { + return mPrefs.getString(PREF_DOWNLOAD_PATH, + DownloadHandler.getDefaultDownloadPath(mContext)); + } + // ----------------------------- // getter/setters for accessibility_preferences.xml // ----------------------------- diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java index 4ec50424..40df4617 100644 --- a/src/com/android/browser/Controller.java +++ b/src/com/android/browser/Controller.java @@ -518,7 +518,7 @@ public class Controller case R.id.download_context_menu_id: DownloadHandler.onDownloadStartNoStream( mActivity, url, view.getSettings().getUserAgentString(), - null, null, null, view.isPrivateBrowsingEnabled()); + null, null, null, view.isPrivateBrowsingEnabled(), 0); break; } break; @@ -1051,7 +1051,7 @@ public class Controller long contentLength) { WebView w = tab.getWebView(); boolean ret = DownloadHandler.onDownloadStart(mActivity, url, userAgent, - contentDisposition, mimetype, referer, w.isPrivateBrowsingEnabled()); + contentDisposition, mimetype, referer, w.isPrivateBrowsingEnabled(), contentLength); if (ret == false && w.copyBackForwardList().getSize() == 0) { // This Tab was opened for the sole purpose of downloading a // file. Remove it. @@ -2238,7 +2238,7 @@ public class Controller saveDataUri(); } else { DownloadHandler.onDownloadStartNoStream(mActivity, mText, mUserAgent, - null, null, null, mPrivateBrowsing); + null, null, null, mPrivateBrowsing, 0); } return true; } diff --git a/src/com/android/browser/DownloadHandler.java b/src/com/android/browser/DownloadHandler.java index 46e6cbcb..e3d31cd0 100644 --- a/src/com/android/browser/DownloadHandler.java +++ b/src/com/android/browser/DownloadHandler.java @@ -19,6 +19,7 @@ package com.android.browser; import android.app.Activity; import android.app.AlertDialog; import android.app.DownloadManager; +import android.app.DownloadManager.Request; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; @@ -29,13 +30,19 @@ import android.content.pm.ResolveInfo; import android.media.MediaFile; import android.net.Uri; import android.net.WebAddress; +import android.os.Bundle; import android.os.Environment; +import android.os.StatFs; +import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; import android.text.TextUtils; import android.util.Log; import android.webkit.CookieManager; import android.webkit.URLUtil; import android.widget.Toast; +import java.io.File; + /** * Handle download requests */ @@ -45,6 +52,9 @@ public class DownloadHandler { com.android.browser.Browser.LOGD_ENABLED; private static final String LOGTAG = "DLHandler"; + private static String mInternalStorage; + private static String mExternalStorage; + private final static String INVALID_PATH = "/storage"; /** * Notify the host application a download should be done, or that @@ -57,9 +67,68 @@ public class DownloadHandler { * @param referer The referer associated with the downloaded url * @param privateBrowsing If the request is coming from a private browsing tab. */ + + public static void startingDownload(Activity activity, + String url, String userAgent, String contentDisposition, + String mimetype, String referer, boolean privateBrowsing, long contentLength, + String filename, String downloadPath) { + // java.net.URI is a lot stricter than KURL so we have to encode some + // extra characters. Fix for b 2538060 and b 1634719 + WebAddress webAddress; + try { + webAddress = new WebAddress(url); + webAddress.setPath(encodePath(webAddress.getPath())); + } catch (Exception e) { + // This only happens for very bad urls, we want to chatch the + // exception here + Log.e(LOGTAG, "Exception trying to parse url:" + url); + return; + } + + String addressString = webAddress.toString(); + Uri uri = Uri.parse(addressString); + final DownloadManager.Request request; + try { + request = new DownloadManager.Request(uri); + } catch (IllegalArgumentException e) { + Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show(); + return; + } + request.setMimeType(mimetype); + // set downloaded file destination to /sdcard/Download. + // or, should it be set to one of several Environment.DIRECTORY* dirs + // depending on mimetype? + try { + setDestinationDir(downloadPath, filename, request); + } catch (Exception e) { + showNoEnoughMemoryDialog(activity); + return; + } + // let this downloaded file be scanned by MediaScanner - so that it can + // show up in Gallery app, for example. + request.allowScanningByMediaScanner(); + request.setDescription(webAddress.getHost()); + // XXX: Have to use the old url since the cookies were stored using the + // old percent-encoded url. + String cookies = CookieManager.getInstance().getCookie(url, privateBrowsing); + request.addRequestHeader("cookie", cookies); + request.addRequestHeader("User-Agent", userAgent); + request.addRequestHeader("Referer", referer); + request.setNotificationVisibility( + DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + final DownloadManager manager = (DownloadManager) activity + .getSystemService(Context.DOWNLOAD_SERVICE); + new Thread("Browser download") { + public void run() { + manager.enqueue(request); + } + }.start(); + showStartDownloadToast(activity); + } + public static boolean onDownloadStart(final Activity activity, final String url, final String userAgent, final String contentDisposition, final String mimetype, - final String referer, final boolean privateBrowsing) { + final String referer, final boolean privateBrowsing, final long contentLength) { // if we're dealing wih A/V content that's not explicitly marked // for download, check if it's streamable. if (contentDisposition == null @@ -88,7 +157,7 @@ public class DownloadHandler { .setPositiveButton(R.string.video_save, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { onDownloadStartNoStream(activity, url, userAgent, contentDisposition, - mimetype, referer, privateBrowsing); + mimetype, referer, privateBrowsing, contentLength); } }) .setNegativeButton(R.string.video_play, new DialogInterface.OnClickListener() { @@ -142,7 +211,7 @@ public class DownloadHandler { } } onDownloadStartNoStream(activity, url, userAgent, contentDisposition, - mimetype, referer, privateBrowsing); + mimetype, referer, privateBrowsing, contentLength); return false; } @@ -187,10 +256,11 @@ public class DownloadHandler { * @param referer The referer associated with the downloaded url * @param privateBrowsing If the request is coming from a private browsing tab. */ - /*package */ static void onDownloadStartNoStream(Activity activity, + /* package */static void onDownloadStartNoStream(Activity activity, String url, String userAgent, String contentDisposition, - String mimetype, String referer, boolean privateBrowsing) { + String mimetype, String referer, boolean privateBrowsing, long contentLength) { + initStorageDefaultPath(activity); String filename = URLUtil.guessFileName(url, contentDisposition, mimetype); @@ -218,63 +288,309 @@ public class DownloadHandler { return; } - // java.net.URI is a lot stricter than KURL so we have to encode some - // extra characters. Fix for b 2538060 and b 1634719 - WebAddress webAddress; - try { - webAddress = new WebAddress(url); - webAddress.setPath(encodePath(webAddress.getPath())); - } catch (Exception e) { - // This only happens for very bad urls, we want to chatch the - // exception here - Log.e(LOGTAG, "Exception trying to parse url:" + url); - return; + if (mimetype == null) { + // We must have long pressed on a link or image to download it. We + // are not sure of the mimetype in this case, so do a head request + new FetchUrlMimeType(activity, url, userAgent, referer, + privateBrowsing, filename).start(); + } else { + startDownloadSettings(activity, url, userAgent, contentDisposition, mimetype, referer, + privateBrowsing, contentLength, filename); } - String addressString = webAddress.toString(); - Uri uri = Uri.parse(addressString); - final DownloadManager.Request request; - try { - request = new DownloadManager.Request(uri); - } catch (IllegalArgumentException e) { - Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show(); - return; + } + + public static void initStorageDefaultPath(Context context) { + mExternalStorage = getExternalStorageDirectory(context); + if (isPhoneStorageSupported()) { + mInternalStorage = Environment.getExternalStorageDirectory().getPath(); + } else { + mInternalStorage = null; } - request.setMimeType(mimetype); - // set downloaded file destination to /sdcard/Download. - // or, should it be set to one of several Environment.DIRECTORY* dirs depending on mimetype? - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename); - // let this downloaded file be scanned by MediaScanner - so that it can - // show up in Gallery app, for example. - request.allowScanningByMediaScanner(); - request.setDescription(webAddress.getHost()); - // XXX: Have to use the old url since the cookies were stored using the - // old percent-encoded url. - String cookies = CookieManager.getInstance().getCookie(url, privateBrowsing); - request.addRequestHeader("cookie", cookies); - request.addRequestHeader("User-Agent", userAgent); - request.addRequestHeader("Referer", referer); - request.setNotificationVisibility( - DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - if (mimetype == null) { - if (TextUtils.isEmpty(addressString)) { - return; + } + + public static void startDownloadSettings(Activity activity, + String url, String userAgent, String contentDisposition, + String mimetype, String referer, boolean privateBrowsing, long contentLength, + String filename) { + Bundle fileInfo = new Bundle(); + fileInfo.putString("url", url); + fileInfo.putString("userAgent", userAgent); + fileInfo.putString("contentDisposition", contentDisposition); + fileInfo.putString("mimetype", mimetype); + fileInfo.putString("referer", referer); + fileInfo.putLong("contentLength", contentLength); + fileInfo.putBoolean("privateBrowsing", privateBrowsing); + fileInfo.putString("filename", filename); + Intent intent = new Intent("android.intent.action.BROWSERDOWNLOAD"); + intent.putExtras(fileInfo); + activity.startActivity(intent); + } + + public static void setAppointedFolder(String downloadPath) { + File file = new File(downloadPath); + if (file.exists()) { + if (!file.isDirectory()) { + throw new IllegalStateException(file.getAbsolutePath() + + " already exists and is not a directory"); } - // We must have long pressed on a link or image to download it. We - // are not sure of the mimetype in this case, so do a head request - new FetchUrlMimeType(activity, request, addressString, cookies, - userAgent).start(); } else { - final DownloadManager manager - = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE); - new Thread("Browser download") { - public void run() { - manager.enqueue(request); - } - }.start(); + if (!file.mkdir()) { + throw new IllegalStateException("Unable to create directory: " + + file.getAbsolutePath()); + } + } + } + + private static void setDestinationDir(String downloadPath, String filename, Request request) { + File file = new File(downloadPath); + if (file.exists()) { + if (!file.isDirectory()) { + throw new IllegalStateException(file.getAbsolutePath() + + " already exists and is not a directory"); + } + } else { + if (!file.mkdir()) { + throw new IllegalStateException("Unable to create directory: " + + file.getAbsolutePath()); + } + } + setDestinationFromBase(file, filename, request); + } + + private static void setDestinationFromBase(File file, String filename, Request request) { + if (filename == null) { + throw new NullPointerException("filename cannot be null"); + } + request.setDestinationUri(Uri.withAppendedPath(Uri.fromFile(file), filename)); + } + + public static void fileExistQueryDialog(Activity activity) { + new AlertDialog.Builder(activity) + .setTitle(R.string.download_file_exist) + .setIcon(android.R.drawable.ic_dialog_info) + .setMessage(R.string.download_file_exist_msg) + // if yes, delete existed file and start new download thread + .setPositiveButton(R.string.ok, null) + // if no, do nothing at all + .show(); + } + + public static long getAvailableMemory(String root) { + StatFs stat = new StatFs(root); + final long LEFT10MByte = 2560; + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks() - LEFT10MByte; + return availableBlocks * blockSize; + } + + public static void showNoEnoughMemoryDialog(Activity mContext) { + new AlertDialog.Builder(mContext) + .setTitle(R.string.download_no_enough_memory) + .setIconAttribute(android.R.attr.alertDialogIcon) + .setMessage(R.string.download_no_enough_memory) + .setPositiveButton(R.string.ok, null) + .show(); + } + + public static boolean manageNoEnoughMemory(Activity mContext, long contentLength, String root) { + Log.i(LOGTAG, "----------- download file contentLength is ------------>" + contentLength); + long mAvailableBytes = getAvailableMemory(root); + if (mAvailableBytes > 0) { + if (contentLength > mAvailableBytes) { + showNoEnoughMemoryDialog(mContext); + return true; + } + } else { + showNoEnoughMemoryDialog(mContext); + return true; } + return false; + } + + public static void showStartDownloadToast(Activity activity) { + Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS); + activity.startActivity(intent); Toast.makeText(activity, R.string.download_pending, Toast.LENGTH_SHORT) .show(); } + /** + * wheather the storage status OK for download file + * + * @param activity + * @param filename the download file's name + * @param downloadPath the download file's path will be in + * @return boolean true is ok,and false is not + */ + public static boolean isStorageStatusOK(Activity activity, String filename, String downloadPath) { + if (downloadPath.equals(INVALID_PATH)) { + new AlertDialog.Builder(activity) + .setTitle(R.string.path_wrong) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.invalid_path) + .setPositiveButton(R.string.ok, null) + .show(); + return false; + } + + if (!(isPhoneStorageSupported() && downloadPath.contains(mInternalStorage))) { + String status = getExternalStorageState(activity); + if (!status.equals(Environment.MEDIA_MOUNTED)) { + int title; + String msg; + + // Check to see if the SDCard is busy, same as the music app + if (status.equals(Environment.MEDIA_SHARED)) { + msg = activity.getString(R.string.download_sdcard_busy_dlg_msg); + title = R.string.download_sdcard_busy_dlg_title; + } else { + msg = activity.getString(R.string.download_no_sdcard_dlg_msg, filename); + title = R.string.download_no_sdcard_dlg_title; + } + + new AlertDialog.Builder(activity) + .setTitle(title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(msg) + .setPositiveButton(R.string.ok, null) + .show(); + return false; + } + } else { + String status = Environment.getExternalStorageState(); + if (!status.equals(Environment.MEDIA_MOUNTED)) { + int mTitle = R.string.download_path_unavailable_dlg_title; + String mMsg = activity.getString(R.string.download_path_unavailable_dlg_msg); + new AlertDialog.Builder(activity) + .setTitle(mTitle) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(mMsg) + .setPositiveButton(R.string.ok, null) + .show(); + return false; + } + } + return true; + } + + /** + * wheather support Phone Storage + * + * @return boolean true support Phone Storage ,false will be not + */ + public static boolean isPhoneStorageSupported() { + return true; + } + + /** + * show Dialog to warn filename is null + * + * @param activity + */ + public static void showFilenameEmptyDialog(Activity activity) { + new AlertDialog.Builder(activity) + .setTitle(R.string.filename_empty_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.filename_empty_msg) + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + } + }) + .show(); + } + + /** + * get the filename except the suffix and dot + * + * @return String the filename except suffix and dot + */ + public static String getFilenameBase(String filename) { + int dotindex = filename.lastIndexOf('.'); + if (dotindex != -1) { + return filename.substring(0, dotindex); + } else { + return ""; + } + } + + /** + * get the filename's extension from filename + * + * @param filename the download filename, may be the user entered + * @return String the filename's extension + */ + public static String getFilenameExtension(String filename) { + int dotindex = filename.lastIndexOf('.'); + if (dotindex != -1) { + return filename.substring(dotindex + 1); + } else { + return ""; + } + } + + public static String getDefaultDownloadPath(Context context) { + String defaultDownloadPath; + + String defaultStorage; + if (isPhoneStorageSupported()) { + defaultStorage = Environment.getExternalStorageDirectory().getPath(); + } else { + defaultStorage = getExternalStorageDirectory(context); + } + + defaultDownloadPath = defaultStorage + context.getString(R.string.default_savepath_name); + Log.e(LOGTAG, "defaultStorage directory is : " + defaultDownloadPath); + return defaultDownloadPath; + } + + /** + * translate the directory name into a name which is easy to know for user + * + * @param activity + * @param downloadPath + * @return String + */ + public static String getDownloadPathForUser(Activity activity, String downloadPath) { + if (downloadPath == null) { + return downloadPath; + } + final String phoneStorageDir; + final String sdCardDir = getExternalStorageDirectory(activity); + if (isPhoneStorageSupported()) { + phoneStorageDir = Environment.getExternalStorageDirectory().getPath(); + } else { + phoneStorageDir = null; + } + + if (downloadPath.startsWith(sdCardDir)) { + String sdCardLabel = activity.getResources().getString( + R.string.download_path_sd_card_label); + downloadPath = downloadPath.replace(sdCardDir, sdCardLabel); + } else if ((phoneStorageDir != null) && downloadPath.startsWith(phoneStorageDir)) { + String phoneStorageLabel = activity.getResources().getString( + R.string.download_path_phone_stroage_label); + downloadPath = downloadPath.replace(phoneStorageDir, phoneStorageLabel); + } + return downloadPath; + } + + private static String getExternalStorageDirectory(Context context) { + String sd = null; + StorageManager mStorageManager = (StorageManager) context + .getSystemService(Context.STORAGE_SERVICE); + StorageVolume[] volumes = mStorageManager.getVolumeList(); + for (int i = 0; i < volumes.length; i++) { + if (volumes[i].isRemovable() && volumes[i].allowMassStorage()) { + sd = volumes[i].getPath(); + } + } + return sd; + } + + private static String getExternalStorageState(Context context) { + StorageManager mStorageManager = (StorageManager) context + .getSystemService(Context.STORAGE_SERVICE); + return mStorageManager.getVolumeState(getExternalStorageDirectory(context)); + } } diff --git a/src/com/android/browser/DownloadSettings.java b/src/com/android/browser/DownloadSettings.java new file mode 100644 index 00000000..c1ddcb67 --- /dev/null +++ b/src/com/android/browser/DownloadSettings.java @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.browser; + +import java.io.File; + +import android.app.Activity; +import android.content.Intent; +import java.lang.Thread; +import android.net.Uri; +import android.os.Bundle; +import android.text.format.*; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.view.Window; +import android.widget.Toast; +import android.text.TextUtils; + +public class DownloadSettings extends Activity { + + private EditText downloadFilenameET; + private EditText downloadPathET; + private TextView downloadEstimateSize; + private TextView downloadEstimateTime; + private Button downloadStart; + private Button downloadCancel; + private String url; + private String userAgent; + private String contentDisposition; + private String mimetype; + private String referer; + private String filenameBase; + private String filename; + private String filenameExtension; + private boolean privateBrowsing; + private long contentLength; + private String downloadPath; + private String downloadPathForUser; + private static final int downloadRate = (1024 * 100 * 60);// Download Rate + // 100KB/s + private final static String LOGTAG = "DownloadSettings"; + private final static int DOWNLOAD_PATH = 0; + private boolean isDownloadStarted = false; + + private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET"; + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // initial the DownloadSettings view + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.download_settings); + downloadFilenameET = (EditText) findViewById(R.id.download_filename_edit); + downloadPathET = (EditText) findViewById(R.id.download_filepath_selected); + downloadEstimateSize = (TextView) findViewById(R.id.download_estimate_size_content); + downloadEstimateTime = (TextView) findViewById(R.id.download_estimate_time_content); + downloadStart = (Button) findViewById(R.id.download_start); + downloadCancel = (Button) findViewById(R.id.download_cancle); + downloadPathET.setOnClickListener(downloadPathListener); + downloadStart.setOnClickListener(downloadStartListener); + downloadCancel.setOnClickListener(downloadCancelListener); + + // get the bundle from Intent + Intent intent = getIntent(); + Bundle fileInfo = intent.getExtras(); + url = fileInfo.getString("url"); + userAgent = fileInfo.getString("userAgent"); + contentDisposition = fileInfo.getString("contentDisposition"); + mimetype = fileInfo.getString("mimetype"); + referer = fileInfo.getString("referer"); + contentLength = fileInfo.getLong("contentLength"); + privateBrowsing = fileInfo.getBoolean("privateBrowsing"); + filename = fileInfo.getString("filename"); + + // download filenamebase's length is depended on filenameLength's values + // if filenamebase.length >= flienameLength, destroy the last string! + + filenameBase = DownloadHandler.getFilenameBase(filename); + if (filenameBase.length() >= (BrowserUtils.FILENAME_MAX_LENGTH)) { + filenameBase = filenameBase.substring(0, BrowserUtils.FILENAME_MAX_LENGTH); + } + + // warring when user enter more over letters into the EditText + BrowserUtils.maxLengthFilter(DownloadSettings.this, downloadFilenameET, + BrowserUtils.FILENAME_MAX_LENGTH); + + downloadFilenameET.setText(filenameBase); + downloadPath = BrowserSettings.getInstance().getDownloadPath(); + downloadPathForUser = DownloadHandler.getDownloadPathForUser(DownloadSettings.this, + downloadPath); + setDownloadPathForUserText(downloadPathForUser); + setDownloadFileSizeText(); + setDownloadFileTimeText(); + + } + + private OnClickListener downloadPathListener = new OnClickListener() { + + @Override + public void onClick(View v) { + + // start filemanager for getting download path + try { + Intent downloadPathIntent = new Intent("com.android.fileexplorer.action.DIR_SEL"); + DownloadSettings.this.startActivityForResult(downloadPathIntent, DOWNLOAD_PATH); + } catch (Exception e) { + String err_msg = getString(R.string.activity_not_found, + "com.android.fileexplorer.action.DIR_SEL"); + Toast.makeText(DownloadSettings.this, err_msg, Toast.LENGTH_LONG).show(); + } + + } + }; + + private OnClickListener downloadStartListener = new OnClickListener() { + + @Override + public void onClick(View v) { + filenameBase = getFilenameBaseFromUserEnter(); + // check the filename user enter is null or not + if (filenameBase.length() <= 0) { + DownloadHandler.showFilenameEmptyDialog(DownloadSettings.this); + return; + } + + filenameExtension = DownloadHandler.getFilenameExtension(filename); + filename = filenameBase + "." + filenameExtension; + + // check the storage status + if (!DownloadHandler.isStorageStatusOK(DownloadSettings.this, filename, downloadPath)) { + return; + } + + // check the storage memory enough or not + try { + DownloadHandler.setAppointedFolder(downloadPath); + } catch (Exception e) { + DownloadHandler.showNoEnoughMemoryDialog(DownloadSettings.this); + return; + } + boolean isNoEnoughMemory = DownloadHandler.manageNoEnoughMemory(DownloadSettings.this, + contentLength, downloadPath); + if (isNoEnoughMemory) { + return; + } + + // check the download file is exist or not + String fullFilename = downloadPath + "/" + filename; + if (mimetype != null && new File(fullFilename).exists()) { + DownloadHandler.fileExistQueryDialog(DownloadSettings.this); + return; + } + + // staring downloading + DownloadHandler.startingDownload(DownloadSettings.this, + url, userAgent, contentDisposition, + mimetype, referer, privateBrowsing, contentLength, + Uri.encode(filename), downloadPath); + isDownloadStarted = true; + } + }; + + private OnClickListener downloadCancelListener = new OnClickListener() { + + @Override + public void onClick(View v) { + finish(); + } + }; + + protected void onDestroy() { + super.onDestroy(); + } + + protected void onPause() { + super.onPause(); + if (isDownloadStarted) { + finish(); + } + } + + protected void onResume() { + super.onResume(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + + if (DOWNLOAD_PATH == requestCode) { + if (resultCode == Activity.RESULT_OK && intent != null) { + downloadPath = intent.getStringExtra("result_dir_sel"); + if (downloadPath != null) { + String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET); + if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) { + if (downloadPath.startsWith("/storage/sdcard0")) + downloadPath = downloadPath.replace("/storage/sdcard0", + "/storage/emulated/0"); + if (downloadPath.startsWith("/storage/emulated/legacy")) + downloadPath = downloadPath.replace("/storage/emulated/legacy", + "/storage/emulated/0"); + } + downloadPathForUser = DownloadHandler.getDownloadPathForUser( + DownloadSettings.this, downloadPath); + setDownloadPathForUserText(downloadPathForUser); + } + } + } + } + + /** + * show download path for user + * + * @param downloadPath the download path user can see + */ + private void setDownloadPathForUserText(String downloadPathForUser) { + downloadPathET.setText(downloadPathForUser); + } + + /** + * get the filename from user select the download path + * + * @return String the filename from user selected + */ + private String getFilenameBaseFromUserEnter() { + return downloadFilenameET.getText().toString(); + } + + /** + * set the download file size for user to be known + */ + private void setDownloadFileSizeText() { + String sizeText; + if (contentLength <= 0) { + sizeText = getString(R.string.unknow_length); + } else { + sizeText = getDownloadFileSize(); + } + downloadEstimateSize.setText(sizeText); + + } + + /** + * set the time which downloaded this file will be estimately use; + */ + private void setDownloadFileTimeText() { + String neededTimeText; + if (contentLength <= 0) { + neededTimeText = getString(R.string.unknow_length); + } else { + neededTimeText = getNeededTime() + getString(R.string.time_min); + } + downloadEstimateTime.setText(neededTimeText); + } + + /** + * count the download file's size and format the values + * + * @return String the format values + */ + private String getDownloadFileSize() { + String currentSizeText = ""; + if (contentLength > 0) { + currentSizeText = Formatter.formatFileSize(DownloadSettings.this, contentLength); + } + return currentSizeText; + } + + /** + * get the time download this file will be use,and format this time values + * + * @return long the valses of time which download this file will be use + */ + private long getNeededTime() { + long timeNeeded = contentLength / downloadRate; + if (timeNeeded < 1) { + timeNeeded = 1; + } + Log.e(LOGTAG, "TimeNeeded:" + timeNeeded + "min"); + // return the time like 5 min, not 5 s; + return timeNeeded; + } +} diff --git a/src/com/android/browser/FetchUrlMimeType.java b/src/com/android/browser/FetchUrlMimeType.java index 33b58086..28bfc800 100644 --- a/src/com/android/browser/FetchUrlMimeType.java +++ b/src/com/android/browser/FetchUrlMimeType.java @@ -22,14 +22,15 @@ import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpHead; import org.apache.http.conn.params.ConnRouteParams; -import android.app.DownloadManager; +import android.app.Activity; import android.content.Context; import android.net.Proxy; +import android.net.Uri; import android.net.http.AndroidHttpClient; -import android.os.Environment; +import android.text.TextUtils; import android.util.Log; +import android.webkit.CookieManager; import android.webkit.MimeTypeMap; -import android.webkit.URLUtil; import java.io.IOException; @@ -48,18 +49,23 @@ class FetchUrlMimeType extends Thread { private final static String LOGTAG = "FetchUrlMimeType"; private Context mContext; - private DownloadManager.Request mRequest; private String mUri; - private String mCookies; private String mUserAgent; + private String mFilename; + private String mReferer; + private Activity mActivity; + private boolean mPrivateBrowsing; + private long mContentLength; - public FetchUrlMimeType(Context context, DownloadManager.Request request, - String uri, String cookies, String userAgent) { - mContext = context.getApplicationContext(); - mRequest = request; - mUri = uri; - mCookies = cookies; + public FetchUrlMimeType(Activity activity, String url, String userAgent, + String referer, boolean privateBrowsing, String filename) { + mActivity = activity; + mContext = activity.getApplicationContext(); + mUri = url; mUserAgent = userAgent; + mPrivateBrowsing = privateBrowsing; + mFilename = filename; + mReferer = referer; } @Override @@ -80,13 +86,16 @@ class FetchUrlMimeType extends Thread { } HttpHead request = new HttpHead(mUri); - if (mCookies != null && mCookies.length() > 0) { - request.addHeader("Cookie", mCookies); + String cookies = CookieManager.getInstance().getCookie(mUri, mPrivateBrowsing); + if (cookies != null && cookies.length() > 0) { + request.addHeader("Cookie", cookies); } HttpResponse response; + String filename = mFilename; String mimeType = null; String contentDisposition = null; + String contentLength = null; try { response = client.execute(request); // We could get a redirect here, but if we do lets let @@ -101,6 +110,10 @@ class FetchUrlMimeType extends Thread { mimeType = mimeType.substring(0, semicolonIndex); } } + Header contentLengthHeader = response.getFirstHeader("Content-Length"); + if (contentLengthHeader != null) { + contentLength = contentLengthHeader.getValue(); + } Header contentDispositionHeader = response.getFirstHeader("Content-Disposition"); if (contentDispositionHeader != null) { contentDisposition = contentDispositionHeader.getValue(); @@ -114,26 +127,150 @@ class FetchUrlMimeType extends Thread { client.close(); } - if (mimeType != null) { - if (mimeType.equalsIgnoreCase("text/plain") || - mimeType.equalsIgnoreCase("application/octet-stream")) { - String newMimeType = - MimeTypeMap.getSingleton().getMimeTypeFromExtension( - MimeTypeMap.getFileExtensionFromUrl(mUri)); - if (newMimeType != null) { - mimeType = newMimeType; - mRequest.setMimeType(newMimeType); - } - } - String filename = URLUtil.guessFileName(mUri, contentDisposition, - mimeType); - mRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename); - } - - // Start the download - DownloadManager manager = (DownloadManager) mContext.getSystemService( - Context.DOWNLOAD_SERVICE); - manager.enqueue(mRequest); + if (mimeType != null) { + Log.e(LOGTAG, "-----------the mimeType from http header is ------------->" + mimeType); + if (mimeType.equalsIgnoreCase("text/plain") || + mimeType.equalsIgnoreCase("application/octet-stream")) { + String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension( + MimeTypeMap.getFileExtensionFromUrl(mUri)); + if (newMimeType != null) { + mimeType = newMimeType; + } + } + + String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); + if (fileExtension == null || (fileExtension != null && fileExtension.equals("bin"))) { + fileExtension = MimeTypeMap.getFileExtensionFromUrl(mUri); + if (fileExtension == null) { + fileExtension = "bin"; + } + } + filename = DownloadHandler.getFilenameBase(filename) + "." + fileExtension; + + } else { + String fileExtension = getFileExtensionFromUrlEx(mUri); + if (fileExtension == "") { + fileExtension = "bin"; + } + String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension); + if (newMimeType != null) { + mimeType = newMimeType; + } + filename = guessFileNameEx(mUri, contentDisposition, mimeType); + + } + + if (contentLength != null) { + mContentLength = Long.parseLong(contentLength); + } else { + mContentLength = 0; + } + + DownloadHandler.startDownloadSettings(mActivity, mUri, mUserAgent, contentDisposition, + mimeType, mReferer, mPrivateBrowsing, mContentLength, filename); + } + + /** + * when we can not parse MineType and Filename from the header of http body + * ,Call the fallowing functions for this matter + * getFileExtensionFromUrlEx(String url) : get the file Extension from Url + * guessFileNameEx() : get the file name from url Note: this modified for + * download http://www.baidu.com girl picture error extension and error + * filename + */ + private String getFileExtensionFromUrlEx(String url) { + Log.e("FetchUrlMimeType", + "--------can not get mimetype from http header, the URL is ---------->" + url); + if (!TextUtils.isEmpty(url)) { + int fragment = url.lastIndexOf('#'); + if (fragment > 0) { + url = url.substring(0, fragment); + } + + int filenamePos = url.lastIndexOf('/'); + String filename = + 0 <= filenamePos ? url.substring(filenamePos + 1) : url; + Log.e(LOGTAG, + "--------can not get mimetype from http header, the temp filename is----------" + + filename); + // if the filename contains special characters, we don't + // consider it valid for our matching purposes: + if (!filename.isEmpty()) { + int dotPos = filename.lastIndexOf('.'); + if (0 <= dotPos) { + return filename.substring(dotPos + 1); + } + } + } + + return ""; + } + + private String guessFileNameEx(String url, String contentDisposition, String mimeType) { + String filename = null; + String extension = null; + + // If all the other http-related approaches failed, use the plain uri + if (filename == null) { + String decodedUrl = Uri.decode(url); + if (decodedUrl != null) { + if (!decodedUrl.endsWith("/")) { + int index = decodedUrl.lastIndexOf('/') + 1; + if (index > 0) { + filename = decodedUrl.substring(index); + } + } + } + } + + // Finally, if couldn't get filename from URI, get a generic filename + if (filename == null) { + filename = "downloadfile"; + } + + // Split filename between base and extension + // Add an extension if filename does not have one + int dotIndex = filename.indexOf('.'); + if (dotIndex < 0) { + if (mimeType != null) { + extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); + if (extension != null) { + extension = "." + extension; + } + } + if (extension == null) { + if (mimeType != null && mimeType.toLowerCase().startsWith("text/")) { + if (mimeType.equalsIgnoreCase("text/html")) { + extension = ".html"; + } else { + extension = ".txt"; + } + } else { + extension = ".bin"; + } + } + } else { + if (mimeType != null) { + // Compare the last segment of the extension against the mime + // type. + // If there's a mismatch, discard the entire extension. + int lastDotIndex = filename.lastIndexOf('.'); + String typeFromExt = MimeTypeMap.getSingleton().getMimeTypeFromExtension( + filename.substring(lastDotIndex + 1)); + if (typeFromExt != null && !typeFromExt.equalsIgnoreCase(mimeType)) { + extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType); + if (extension != null) { + extension = "." + extension; + } + } + } + if (extension == null) { + extension = filename.substring(dotIndex); + } + filename = filename.substring(0, dotIndex); + } + + return filename + extension; } } diff --git a/src/com/android/browser/PreferenceKeys.java b/src/com/android/browser/PreferenceKeys.java index 18280327..ffbb39ab 100644 --- a/src/com/android/browser/PreferenceKeys.java +++ b/src/com/android/browser/PreferenceKeys.java @@ -47,7 +47,8 @@ public interface PreferenceKeys { static final String PREF_SEARCH_ENGINE = "search_engine"; static final String PREF_WEBSITE_SETTINGS = "website_settings"; static final String PREF_ALLOW_APP_TABS = "allow_apptabs"; - + // Keys for download path settings + static final String PREF_DOWNLOAD_PATH = "download_path_setting_screen"; // ---------------------- // Keys for debug_preferences.xml // ---------------------- diff --git a/src/com/android/browser/preferences/AdvancedPreferencesFragment.java b/src/com/android/browser/preferences/AdvancedPreferencesFragment.java index 0a97ba04..acc26ce2 100644 --- a/src/com/android/browser/preferences/AdvancedPreferencesFragment.java +++ b/src/com/android/browser/preferences/AdvancedPreferencesFragment.java @@ -17,11 +17,16 @@ package com.android.browser.preferences; import com.android.browser.BrowserActivity; +import com.android.browser.BrowserSettings; +import com.android.browser.DownloadHandler; import com.android.browser.PreferenceKeys; import com.android.browser.R; +import android.app.Activity; import android.content.Intent; import android.content.res.Resources; +import android.content.SharedPreferences.Editor; +import android.net.Uri; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; @@ -31,6 +36,7 @@ import android.util.Log; import android.webkit.GeolocationPermissions; import android.webkit.ValueCallback; import android.webkit.WebStorage; +import android.widget.Toast; import java.util.Map; import java.util.Set; @@ -38,6 +44,7 @@ import java.util.Set; public class AdvancedPreferencesFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener { + private static final int DOWNLOAD_PATH_RESULT_CODE = 1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -68,6 +75,62 @@ public class AdvancedPreferencesFragment extends PreferenceFragment e = findPreference(PreferenceKeys.PREF_PLUGIN_STATE); e.setOnPreferenceChangeListener(this); updateListPreferenceSummary((ListPreference) e); + onInitdownloadSettingsPreference(); + } + + private void onInitdownloadSettingsPreference() { + addPreferencesFromResource(R.xml.download_settings_preferences); + PreferenceScreen downloadPathPreset = + (PreferenceScreen) findPreference(PreferenceKeys.PREF_DOWNLOAD_PATH); + downloadPathPreset.setOnPreferenceClickListener(onClickDownloadPathSettings()); + + String downloadPath = downloadPathPreset.getSharedPreferences(). + getString(PreferenceKeys.PREF_DOWNLOAD_PATH, + BrowserSettings.getInstance().getDownloadPath()); + String downloadPathForUser = DownloadHandler.getDownloadPathForUser(this.getActivity(), + downloadPath); + downloadPathPreset.setSummary(downloadPathForUser); + } + + private Preference.OnPreferenceClickListener onClickDownloadPathSettings() { + return new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + try { + Intent i = new Intent("com.android.fileexplorer.action.DIR_SEL"); + AdvancedPreferencesFragment.this.startActivityForResult(i, + DOWNLOAD_PATH_RESULT_CODE); + } catch (Exception e) { + String err_msg = getResources().getString(R.string.activity_not_found, + "com.android.fileexplorer.action.DIR_SEL"); + Toast.makeText(getActivity(), err_msg, Toast.LENGTH_LONG).show(); + } + return true; + } + }; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == DOWNLOAD_PATH_RESULT_CODE) { + if (resultCode == Activity.RESULT_OK && data != null) { + String downloadPath = data.getStringExtra("result_dir_sel"); + if (downloadPath != null) { + PreferenceScreen downloadPathPreset = + (PreferenceScreen) findPreference(PreferenceKeys.PREF_DOWNLOAD_PATH); + Editor editor = downloadPathPreset.getEditor(); + editor.putString(PreferenceKeys.PREF_DOWNLOAD_PATH, downloadPath); + editor.apply(); + String downloadPathForUser = DownloadHandler.getDownloadPathForUser( + this.getActivity(), downloadPath); + downloadPathPreset.setSummary(downloadPathForUser); + } + + return; + } + } + return; } void updateListPreferenceSummary(ListPreference e) { @@ -154,4 +217,4 @@ public class AdvancedPreferencesFragment extends PreferenceFragment return ""; } -}
\ No newline at end of file +} |