| /* |
| * Copyright (c) 2013,2014, 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 com.android.browser.R; |
| |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Environment; |
| 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.webkit.MimeTypeMap; |
| import android.text.TextUtils; |
| |
| import com.android.browser.reflect.ReflectHelper; |
| |
| 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"; |
| private static final String APK_TYPE="apk"; |
| private static final String OCTET_STREAM = "application/octet-stream"; |
| |
| 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_cancel); |
| 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); |
| |
| String filenameExtension = DownloadHandler.getFilenameExtension(filename); |
| |
| // introspect for octet stream mimetype what type of file extension it has |
| // and reassign mimetype |
| if (mimetype == null || mimetype.isEmpty() || mimetype.equals(OCTET_STREAM)) { |
| |
| String updatedFileName = filenameBase + "." + filenameExtension; |
| Object[] params = {updatedFileName}; |
| Class[] type = new Class[] {String.class}; |
| mimetype = (String) ReflectHelper.invokeMethod("android.media.MediaFile", |
| "getMimeTypeForFile", type, params); |
| } |
| |
| //Add special check for .apk files with octet-stream mimetype |
| if (filenameExtension.equals(APK_TYPE) && mimetype != null && mimetype.equals(OCTET_STREAM)) { |
| mimetype = "application/vnd.android.package-archive"; |
| } |
| |
| // last way to fetch for mimetype if its still null |
| if (mimetype == null || mimetype.isEmpty()) |
| mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(filenameExtension); |
| |
| downloadPath = chooseFolderFromMimeType(BrowserSettings.getInstance().getDownloadPath(), |
| mimetype); |
| downloadPathForUser = DownloadHandler.getDownloadPathForUser(DownloadSettings.this, |
| downloadPath); |
| |
| autoupdateFileName(filenameBase, DownloadHandler.getFilenameExtension(filename), downloadPath); |
| setDownloadPathForUserText(downloadPathForUser); |
| setDownloadFileSizeText(); |
| setDownloadFileTimeText(); |
| } |
| |
| private void autoupdateFileName(String filenameBase, String extension, String downloadPath) { |
| String fullPath = downloadPath + "/" + filenameBase + "." + extension; |
| int count = 1; |
| String newFilenameBase = ""; |
| |
| while(new File(fullPath).exists()) { |
| newFilenameBase = filenameBase+"-"+count++; |
| fullPath = downloadPath + "/" + newFilenameBase + "." + extension; |
| } |
| |
| if(!TextUtils.isEmpty(newFilenameBase)) { |
| filenameBase = newFilenameBase; |
| } |
| |
| downloadFilenameET.setText(filenameBase); |
| } |
| |
| private OnClickListener downloadPathListener = new OnClickListener() { |
| |
| @Override |
| public void onClick(View v) { |
| |
| final String filemanagerIntent = |
| getResources().getString(R.string.def_intent_file_manager); |
| if (!TextUtils.isEmpty(filemanagerIntent)) { |
| // start filemanager for getting download path |
| try { |
| Intent downloadPathIntent = new Intent(filemanagerIntent); |
| DownloadSettings.this.startActivityForResult(downloadPathIntent, DOWNLOAD_PATH); |
| } catch (Exception e) { |
| String err_msg = getString(R.string.activity_not_found, |
| filemanagerIntent); |
| Toast.makeText(DownloadSettings.this, err_msg, Toast.LENGTH_LONG).show(); |
| } |
| } else { |
| Log.e(LOGTAG, "File Manager intent not defined !!"); |
| } |
| |
| } |
| }; |
| |
| private OnClickListener downloadStartListener = new OnClickListener() { |
| |
| @Override |
| public void onClick(View v) { |
| filenameBase = getFilenameBaseFromUserEnter(); |
| // check the filename user enter is null or not |
| if (TextUtils.isEmpty(filenameBase) || TextUtils.isEmpty(downloadPath)) { |
| 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(contentLength, |
| downloadPath); |
| if (isNoEnoughMemory) { |
| DownloadHandler.showNoEnoughMemoryDialog(DownloadSettings.this); |
| 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) { |
| final String result_dir_sel = |
| getResources().getString(R.string.def_file_manager_result_dir); |
| downloadPath = intent.getStringExtra(result_dir_sel); |
| // Fallback logic to stock browser |
| if (downloadPath == null) { |
| Uri uri = intent.getData(); |
| if(uri != null) |
| downloadPath = uri.getPath(); |
| } |
| 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); |
| } |
| } |
| } |
| } |
| |
| // Add for carrier feature - download to related folders by mimetype. |
| private static String chooseFolderFromMimeType(String path, String mimeType) { |
| String destinationFolder = null; |
| if (!path.contains(Environment.DIRECTORY_DOWNLOADS) || null == mimeType) |
| return path; |
| if (mimeType.startsWith("audio")) |
| destinationFolder = Environment.DIRECTORY_MUSIC; |
| else if (mimeType.startsWith("video")) |
| destinationFolder = Environment.DIRECTORY_MOVIES; |
| else if (mimeType.startsWith("image")) |
| destinationFolder = Environment.DIRECTORY_PICTURES; |
| if (null != destinationFolder) |
| path = path.replace(Environment.DIRECTORY_DOWNLOADS, destinationFolder); |
| return path; |
| } |
| |
| /** |
| * 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; |
| } |
| } |