summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluxiaol <luxiaol@codeaurora.org>2013-07-22 07:54:49 +0800
committerkaiyiz <kaiyiz@codeaurora.org>2013-08-21 16:03:52 +0800
commit62677b01865f9592696b2a8e56459e5bc99840eb (patch)
tree3d39edc3a0a3cdd6ad67ad24ef0d63c1b8862166
parentcb594a24bd78ab02a2b4fda9c6519dec2fe5ea61 (diff)
downloadandroid_packages_apps_Gello-62677b01865f9592696b2a8e56459e5bc99840eb.tar.gz
android_packages_apps_Gello-62677b01865f9592696b2a8e56459e5bc99840eb.tar.bz2
android_packages_apps_Gello-62677b01865f9592696b2a8e56459e5bc99840eb.zip
Browser: add save path setting feature and full indicator
1. The saving path can be preseted, both the internal storage and the SD card are supported 2. Reminder if the download file size exceed the available memory. CRs-fixed: 507953 507954 Change-Id: Ic2f807cb0ee2408cc6e4455a4c67bab5a0d01a8f
-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
+}