summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml12
-rw-r--r--res/layout/download_settings.xml203
-rw-r--r--res/values-zh-rCN/strings.xml27
-rw-r--r--res/values/strings.xml29
-rw-r--r--res/xml/download_settings_preferences.xml42
-rw-r--r--src/com/android/browser/BrowserSettings.java5
-rw-r--r--src/com/android/browser/Controller.java6
-rw-r--r--src/com/android/browser/DownloadHandler.java424
-rw-r--r--src/com/android/browser/DownloadSettings.java312
-rw-r--r--src/com/android/browser/FetchUrlMimeType.java203
-rw-r--r--src/com/android/browser/PreferenceKeys.java3
-rw-r--r--src/com/android/browser/preferences/AdvancedPreferencesFragment.java65
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
+}