blob: aa528d226ec39dafdd0397d6a6e8d1e276733396 [file] [log] [blame]
luxiaol62677b02013-07-22 07:54:49 +08001/*
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -07002 * Copyright (c) 2013,2014, The Linux Foundation. All rights reserved.
luxiaol62677b02013-07-22 07:54:49 +08003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
Bijan Amirzada41242f22014-03-21 12:12:18 -070030package com.android.browser;
luxiaol62677b02013-07-22 07:54:49 +080031
32import java.io.File;
33
34import android.app.Activity;
35import android.content.Intent;
36import java.lang.Thread;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080037
Bijan Amirzada41242f22014-03-21 12:12:18 -070038import com.android.browser.R;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080039
luxiaol62677b02013-07-22 07:54:49 +080040import android.net.Uri;
41import android.os.Bundle;
kaiyizf1a66762013-09-16 16:59:43 +080042import android.os.Environment;
luxiaol62677b02013-07-22 07:54:49 +080043import android.text.format.*;
44import android.util.Log;
45import android.view.View;
46import android.view.View.OnClickListener;
47import android.widget.Button;
48import android.widget.EditText;
jrizzoli700a8672015-10-18 00:15:07 +020049import android.widget.ImageButton;
luxiaol62677b02013-07-22 07:54:49 +080050import android.widget.TextView;
51import android.view.Window;
52import android.widget.Toast;
Axesh R. Ajmeraf9cb0cb2015-04-09 17:23:31 -070053import android.webkit.MimeTypeMap;
luxiaol62677b02013-07-22 07:54:49 +080054import android.text.TextUtils;
Vivek Sekhara3d93b12015-11-21 21:26:33 -080055import android.content.pm.PackageManager;
56import android.Manifest.permission;
Vivek Sekharb7b51df2016-02-06 20:55:00 +010057import android.content.Context;
luxiaol62677b02013-07-22 07:54:49 +080058
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -070059import com.android.browser.reflect.ReflectHelper;
60
luxiaol62677b02013-07-22 07:54:49 +080061public class DownloadSettings extends Activity {
62
63 private EditText downloadFilenameET;
64 private EditText downloadPathET;
65 private TextView downloadEstimateSize;
66 private TextView downloadEstimateTime;
jrizzoli700a8672015-10-18 00:15:07 +020067 private ImageButton downloadStart;
68 private ImageButton downloadCancel;
luxiaol62677b02013-07-22 07:54:49 +080069 private String url;
70 private String userAgent;
71 private String contentDisposition;
72 private String mimetype;
73 private String referer;
Pankaj Garg5762b362015-11-02 07:57:06 -080074 private String authorization;
luxiaol62677b02013-07-22 07:54:49 +080075 private String filenameBase;
76 private String filename;
77 private String filenameExtension;
78 private boolean privateBrowsing;
79 private long contentLength;
80 private String downloadPath;
81 private String downloadPathForUser;
82 private static final int downloadRate = (1024 * 100 * 60);// Download Rate
83 // 100KB/s
84 private final static String LOGTAG = "DownloadSettings";
85 private final static int DOWNLOAD_PATH = 0;
86 private boolean isDownloadStarted = false;
87
88 private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -070089 private static final String APK_TYPE="apk";
90 private static final String OCTET_STREAM = "application/octet-stream";
luxiaol62677b02013-07-22 07:54:49 +080091
Vivek Sekhara3d93b12015-11-21 21:26:33 -080092 private int nextRequestCode = 2000;
93
luxiaol62677b02013-07-22 07:54:49 +080094 protected void onCreate(Bundle savedInstanceState) {
Vivek Sekharb7b51df2016-02-06 20:55:00 +010095 if (!EngineInitializer.isInitialized()) {
96 Log.e(LOGTAG, "Engine not Initialized");
97 EngineInitializer.initializeSync((Context) getApplicationContext());
98 }
luxiaol62677b02013-07-22 07:54:49 +080099 super.onCreate(savedInstanceState);
100 // initial the DownloadSettings view
101 requestWindowFeature(Window.FEATURE_NO_TITLE);
102 setContentView(R.layout.download_settings);
103 downloadFilenameET = (EditText) findViewById(R.id.download_filename_edit);
104 downloadPathET = (EditText) findViewById(R.id.download_filepath_selected);
105 downloadEstimateSize = (TextView) findViewById(R.id.download_estimate_size_content);
106 downloadEstimateTime = (TextView) findViewById(R.id.download_estimate_time_content);
jrizzoli700a8672015-10-18 00:15:07 +0200107 downloadStart = (ImageButton) findViewById(R.id.download_start);
108 downloadCancel = (ImageButton) findViewById(R.id.download_cancel);
luxiaol62677b02013-07-22 07:54:49 +0800109 downloadPathET.setOnClickListener(downloadPathListener);
110 downloadStart.setOnClickListener(downloadStartListener);
111 downloadCancel.setOnClickListener(downloadCancelListener);
112
113 // get the bundle from Intent
114 Intent intent = getIntent();
115 Bundle fileInfo = intent.getExtras();
116 url = fileInfo.getString("url");
117 userAgent = fileInfo.getString("userAgent");
118 contentDisposition = fileInfo.getString("contentDisposition");
119 mimetype = fileInfo.getString("mimetype");
120 referer = fileInfo.getString("referer");
Pankaj Garg5762b362015-11-02 07:57:06 -0800121 authorization = fileInfo.getString("authorization");
luxiaol62677b02013-07-22 07:54:49 +0800122 contentLength = fileInfo.getLong("contentLength");
123 privateBrowsing = fileInfo.getBoolean("privateBrowsing");
124 filename = fileInfo.getString("filename");
125
126 // download filenamebase's length is depended on filenameLength's values
127 // if filenamebase.length >= flienameLength, destroy the last string!
128
129 filenameBase = DownloadHandler.getFilenameBase(filename);
130 if (filenameBase.length() >= (BrowserUtils.FILENAME_MAX_LENGTH)) {
131 filenameBase = filenameBase.substring(0, BrowserUtils.FILENAME_MAX_LENGTH);
132 }
133
134 // warring when user enter more over letters into the EditText
135 BrowserUtils.maxLengthFilter(DownloadSettings.this, downloadFilenameET,
136 BrowserUtils.FILENAME_MAX_LENGTH);
137
138 downloadFilenameET.setText(filenameBase);
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -0700139
140 String filenameExtension = DownloadHandler.getFilenameExtension(filename);
141
Axesh R. Ajmera2e241242014-05-19 15:53:38 -0700142 // introspect for octet stream mimetype what type of file extension it has
143 // and reassign mimetype
144 if (mimetype == null || mimetype.isEmpty() || mimetype.equals(OCTET_STREAM)) {
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -0700145
146 String updatedFileName = filenameBase + "." + filenameExtension;
147 Object[] params = {updatedFileName};
148 Class[] type = new Class[] {String.class};
Bijan Amirzada58383e72014-04-01 14:45:22 -0700149 mimetype = (String) ReflectHelper.invokeMethod("android.media.MediaFile",
Axesh R. Ajmeraf9cb0cb2015-04-09 17:23:31 -0700150 "getMimeTypeForFile", type, params);
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -0700151 }
152
153 //Add special check for .apk files with octet-stream mimetype
Axesh R. Ajmera77258982014-04-02 14:39:09 -0700154 if (filenameExtension.equals(APK_TYPE) && mimetype != null && mimetype.equals(OCTET_STREAM)) {
Axesh R. Ajmera7cfd7a72014-04-01 16:03:42 -0700155 mimetype = "application/vnd.android.package-archive";
156 }
157
Axesh R. Ajmeraf9cb0cb2015-04-09 17:23:31 -0700158 // last way to fetch for mimetype if its still null
159 if (mimetype == null || mimetype.isEmpty())
160 mimetype = MimeTypeMap.getSingleton().getMimeTypeFromExtension(filenameExtension);
161
kaiyizf1a66762013-09-16 16:59:43 +0800162 downloadPath = chooseFolderFromMimeType(BrowserSettings.getInstance().getDownloadPath(),
163 mimetype);
luxiaol62677b02013-07-22 07:54:49 +0800164 downloadPathForUser = DownloadHandler.getDownloadPathForUser(DownloadSettings.this,
165 downloadPath);
Axesh R. Ajmeraf9cb0cb2015-04-09 17:23:31 -0700166
167 autoupdateFileName(filenameBase, DownloadHandler.getFilenameExtension(filename), downloadPath);
luxiaol62677b02013-07-22 07:54:49 +0800168 setDownloadPathForUserText(downloadPathForUser);
169 setDownloadFileSizeText();
170 setDownloadFileTimeText();
luxiaol62677b02013-07-22 07:54:49 +0800171 }
172
Axesh R. Ajmeraf9cb0cb2015-04-09 17:23:31 -0700173 private void autoupdateFileName(String filenameBase, String extension, String downloadPath) {
174 String fullPath = downloadPath + "/" + filenameBase + "." + extension;
175 int count = 1;
176 String newFilenameBase = "";
177
178 while(new File(fullPath).exists()) {
179 newFilenameBase = filenameBase+"-"+count++;
180 fullPath = downloadPath + "/" + newFilenameBase + "." + extension;
181 }
182
183 if(!TextUtils.isEmpty(newFilenameBase)) {
184 filenameBase = newFilenameBase;
185 }
186
187 downloadFilenameET.setText(filenameBase);
188 }
189
luxiaol62677b02013-07-22 07:54:49 +0800190 private OnClickListener downloadPathListener = new OnClickListener() {
191
192 @Override
193 public void onClick(View v) {
194
Vivek Sekharefefe6b2015-01-05 16:01:07 -0800195 final String filemanagerIntent =
196 getResources().getString(R.string.def_intent_file_manager);
197 if (!TextUtils.isEmpty(filemanagerIntent)) {
198 // start filemanager for getting download path
199 try {
200 Intent downloadPathIntent = new Intent(filemanagerIntent);
201 DownloadSettings.this.startActivityForResult(downloadPathIntent, DOWNLOAD_PATH);
202 } catch (Exception e) {
203 String err_msg = getString(R.string.activity_not_found,
204 filemanagerIntent);
205 Toast.makeText(DownloadSettings.this, err_msg, Toast.LENGTH_LONG).show();
206 }
207 } else {
208 Log.e(LOGTAG, "File Manager intent not defined !!");
luxiaol62677b02013-07-22 07:54:49 +0800209 }
210
211 }
212 };
213
214 private OnClickListener downloadStartListener = new OnClickListener() {
215
216 @Override
217 public void onClick(View v) {
218 filenameBase = getFilenameBaseFromUserEnter();
219 // check the filename user enter is null or not
Sagar Dhawan97ed6c92015-07-31 15:36:07 -0700220 if (TextUtils.isEmpty(filenameBase) || TextUtils.isEmpty(downloadPath)) {
luxiaol62677b02013-07-22 07:54:49 +0800221 DownloadHandler.showFilenameEmptyDialog(DownloadSettings.this);
222 return;
223 }
224
225 filenameExtension = DownloadHandler.getFilenameExtension(filename);
226 filename = filenameBase + "." + filenameExtension;
227
228 // check the storage status
229 if (!DownloadHandler.isStorageStatusOK(DownloadSettings.this, filename, downloadPath)) {
230 return;
231 }
232
233 // check the storage memory enough or not
234 try {
235 DownloadHandler.setAppointedFolder(downloadPath);
236 } catch (Exception e) {
237 DownloadHandler.showNoEnoughMemoryDialog(DownloadSettings.this);
238 return;
239 }
kaiyize6a27d02013-08-22 15:08:19 +0800240 boolean isNoEnoughMemory = DownloadHandler.manageNoEnoughMemory(contentLength,
241 downloadPath);
luxiaol62677b02013-07-22 07:54:49 +0800242 if (isNoEnoughMemory) {
kaiyize6a27d02013-08-22 15:08:19 +0800243 DownloadHandler.showNoEnoughMemoryDialog(DownloadSettings.this);
luxiaol62677b02013-07-22 07:54:49 +0800244 return;
245 }
246
247 // check the download file is exist or not
248 String fullFilename = downloadPath + "/" + filename;
249 if (mimetype != null && new File(fullFilename).exists()) {
250 DownloadHandler.fileExistQueryDialog(DownloadSettings.this);
251 return;
252 }
253
Vivek Sekhara3d93b12015-11-21 21:26:33 -0800254 // check for permission
255 if (!hasPermission(permission.WRITE_EXTERNAL_STORAGE)) {
256 requestPermissions(new String[] {permission.WRITE_EXTERNAL_STORAGE},
257 ++nextRequestCode);
258 } else {
259 download();
260 }
luxiaol62677b02013-07-22 07:54:49 +0800261 }
262 };
263
Vivek Sekhara3d93b12015-11-21 21:26:33 -0800264 @Override
265 public void onRequestPermissionsResult(int requestCode,
266 String[] permissions, int[] grantResults) {
267 if (nextRequestCode == requestCode) {
268 if (grantResults.length > 0
269 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
270 download();
271 } else {
272 finish();
273 }
274 }
275 }
276
277 private void download() {
278 // staring downloading
279 DownloadHandler.startingDownload(DownloadSettings.this,
280 url, userAgent, contentDisposition,
281 mimetype, referer, authorization,
282 privateBrowsing, contentLength,
283 Uri.encode(filename), downloadPath);
284 isDownloadStarted = true;
285 }
286
287 private boolean hasPermission(String permission) {
288 return (checkCallingOrSelfPermission(permission)
289 == PackageManager.PERMISSION_GRANTED);
290 }
291
luxiaol62677b02013-07-22 07:54:49 +0800292 private OnClickListener downloadCancelListener = new OnClickListener() {
luxiaol62677b02013-07-22 07:54:49 +0800293 @Override
294 public void onClick(View v) {
295 finish();
296 }
297 };
298
299 protected void onDestroy() {
300 super.onDestroy();
301 }
302
303 protected void onPause() {
304 super.onPause();
305 if (isDownloadStarted) {
306 finish();
307 }
308 }
309
310 protected void onResume() {
311 super.onResume();
Vivek Sekhara3d93b12015-11-21 21:26:33 -0800312 if (isDownloadStarted) {
313 finish();
314 }
luxiaol62677b02013-07-22 07:54:49 +0800315 }
316
317 @Override
318 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Vivek Sekharefefe6b2015-01-05 16:01:07 -0800319
luxiaol62677b02013-07-22 07:54:49 +0800320 if (DOWNLOAD_PATH == requestCode) {
Vivek Sekharefefe6b2015-01-05 16:01:07 -0800321 if (resultCode == Activity.RESULT_OK && intent != null) {
322 final String result_dir_sel =
323 getResources().getString(R.string.def_file_manager_result_dir);
324 downloadPath = intent.getStringExtra(result_dir_sel);
Vivek Sekhar76074ac2014-06-27 16:33:13 -0700325 // Fallback logic to stock browser
326 if (downloadPath == null) {
327 Uri uri = intent.getData();
328 if(uri != null)
329 downloadPath = uri.getPath();
330 }
luxiaol62677b02013-07-22 07:54:49 +0800331 if (downloadPath != null) {
332 String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
333 if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
334 if (downloadPath.startsWith("/storage/sdcard0"))
335 downloadPath = downloadPath.replace("/storage/sdcard0",
336 "/storage/emulated/0");
337 if (downloadPath.startsWith("/storage/emulated/legacy"))
338 downloadPath = downloadPath.replace("/storage/emulated/legacy",
339 "/storage/emulated/0");
340 }
341 downloadPathForUser = DownloadHandler.getDownloadPathForUser(
342 DownloadSettings.this, downloadPath);
343 setDownloadPathForUserText(downloadPathForUser);
344 }
345 }
346 }
347 }
348
kaiyizf1a66762013-09-16 16:59:43 +0800349 // Add for carrier feature - download to related folders by mimetype.
350 private static String chooseFolderFromMimeType(String path, String mimeType) {
351 String destinationFolder = null;
352 if (!path.contains(Environment.DIRECTORY_DOWNLOADS) || null == mimeType)
353 return path;
354 if (mimeType.startsWith("audio"))
355 destinationFolder = Environment.DIRECTORY_MUSIC;
356 else if (mimeType.startsWith("video"))
357 destinationFolder = Environment.DIRECTORY_MOVIES;
358 else if (mimeType.startsWith("image"))
359 destinationFolder = Environment.DIRECTORY_PICTURES;
360 if (null != destinationFolder)
361 path = path.replace(Environment.DIRECTORY_DOWNLOADS, destinationFolder);
362 return path;
363 }
364
luxiaol62677b02013-07-22 07:54:49 +0800365 /**
366 * show download path for user
367 *
368 * @param downloadPath the download path user can see
369 */
370 private void setDownloadPathForUserText(String downloadPathForUser) {
371 downloadPathET.setText(downloadPathForUser);
372 }
373
374 /**
375 * get the filename from user select the download path
376 *
377 * @return String the filename from user selected
378 */
379 private String getFilenameBaseFromUserEnter() {
380 return downloadFilenameET.getText().toString();
381 }
382
383 /**
384 * set the download file size for user to be known
385 */
386 private void setDownloadFileSizeText() {
387 String sizeText;
388 if (contentLength <= 0) {
389 sizeText = getString(R.string.unknow_length);
390 } else {
391 sizeText = getDownloadFileSize();
392 }
393 downloadEstimateSize.setText(sizeText);
394
395 }
396
397 /**
398 * set the time which downloaded this file will be estimately use;
399 */
400 private void setDownloadFileTimeText() {
401 String neededTimeText;
402 if (contentLength <= 0) {
403 neededTimeText = getString(R.string.unknow_length);
404 } else {
405 neededTimeText = getNeededTime() + getString(R.string.time_min);
406 }
407 downloadEstimateTime.setText(neededTimeText);
408 }
409
410 /**
411 * count the download file's size and format the values
412 *
413 * @return String the format values
414 */
415 private String getDownloadFileSize() {
416 String currentSizeText = "";
417 if (contentLength > 0) {
418 currentSizeText = Formatter.formatFileSize(DownloadSettings.this, contentLength);
419 }
420 return currentSizeText;
421 }
422
423 /**
424 * get the time download this file will be use,and format this time values
425 *
426 * @return long the valses of time which download this file will be use
427 */
428 private long getNeededTime() {
429 long timeNeeded = contentLength / downloadRate;
430 if (timeNeeded < 1) {
431 timeNeeded = 1;
432 }
433 Log.e(LOGTAG, "TimeNeeded:" + timeNeeded + "min");
434 // return the time like 5 min, not 5 s;
435 return timeNeeded;
436 }
437}