package org.softeg.slartus.forpdaplus.download; import android.Manifest; import android.app.Activity; import android.app.DownloadManager; import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.ResultReceiver; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; import org.apache.http.HttpEntity; import org.apache.http.cookie.Cookie; import org.softeg.slartus.forpdacommon.FileUtils; import org.softeg.slartus.forpdacommon.NotReportException; import org.softeg.slartus.forpdaplus.App; import org.softeg.slartus.forpdaplus.Client; import org.softeg.slartus.forpdaplus.HttpHelper; import org.softeg.slartus.forpdaplus.R; import org.softeg.slartus.forpdaplus.classes.ActionSelectDialogFragment; import org.softeg.slartus.forpdaplus.classes.DownloadTask; import org.softeg.slartus.forpdaplus.common.AppLog; import org.softeg.slartus.forpdaplus.db.DownloadsTable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; /** * User: slinkin * Date: 16.07.12 * Time: 9:58 */ public class DownloadsService extends IntentService { public static Integer notification_text_color = null; public static float notification_text_size = -1; private final String COLOR_SEARCH_RECURSE_TIP = "SOME_SAMPLE_TEXT"; private final static int BUFFER_SIZE = 1024 * 8; private boolean recurseGroup(ViewGroup gp) { final int count = gp.getChildCount(); for (int i = 0; i < count; ++i) { if (gp.getChildAt(i) instanceof TextView) { final TextView text = (TextView) gp.getChildAt(i); final String szText = text.getText().toString(); if (COLOR_SEARCH_RECURSE_TIP.equals(szText)) { notification_text_color = text.getTextColors().getDefaultColor(); notification_text_size = text.getTextSize(); DisplayMetrics metrics = new DisplayMetrics(); WindowManager systemWM = (WindowManager) getSystemService(Context.WINDOW_SERVICE); systemWM.getDefaultDisplay().getMetrics(metrics); notification_text_size /= metrics.scaledDensity; return true; } } else if (gp.getChildAt(i) instanceof ViewGroup) return recurseGroup((ViewGroup) gp.getChildAt(i)); } return false; } /* private void extractColors() { if (notification_text_color != null) return; try { Notification ntf = new Notification(); //noinspection deprecation ntf.setLatestEventInfo(this, COLOR_SEARCH_RECURSE_TIP, "Utest", null); LinearLayout group = new LinearLayout(this); ViewGroup event = (ViewGroup) ntf.contentView.apply(this, group); recurseGroup(event); group.removeAllViews(); } catch (Exception e) { // notification_text_color = android.R.color.black; } } */ public static final String DOWNLOAD_FILE_ID_KEY = "DownloadFileIdKey"; public static final String DOWNLOAD_FILE_TEMP_NAME_KEY = "DownloadFileTempNameKey"; public static final int UPDATE_PROGRESS = 8344; public DownloadsService() { super("DownloadsService"); } public static String getDownloadDir(Context context) { return App.getInstance().getPreferences().getString("downloads.path", getDefaultDownloadPath()); } public static String getDefaultDownloadPath() { return Environment.getExternalStorageDirectory() + "/download/4pda/".replace("/", File.separator); } @Override protected void onHandleIntent(Intent intent) { int notificationId = intent.getExtras().getInt(DOWNLOAD_FILE_ID_KEY); ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver"); String tempFilePath = intent.getStringExtra(DOWNLOAD_FILE_TEMP_NAME_KEY); downloadFile(receiver, notificationId, tempFilePath); } @Override public void onCreate() { super.onCreate(); } public static void download(final Activity context1, final String url, Boolean finish) { download(context1, url, null, -1, finish); } public static void download(final Activity context1, final String url, final String tempFilePath, final int notificationId, final Boolean finish) { ActionSelectDialogFragment.execute(context1, context1.getString(R.string.download_method), "file.downloaderManagers", context1.getResources().getTextArray(R.array.downloaderManagersArray), context1.getResources().getTextArray(R.array.downloaderManagersValues), new ActionSelectDialogFragment.OkListener() { @Override public void execute(CharSequence value) { try { switch (value.toString()) { case "0":// клиент if (ContextCompat.checkSelfPermission(context1, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) Toast.makeText(context1, R.string.no_permission, Toast.LENGTH_SHORT).show(); else clientDownload(context1, url, tempFilePath, notificationId); if (finish) context1.finish(); break; case "1": // системный new GetTempUrlTask(context1, new GetTempUrlTask.onOpenUrlInterface() { @Override public void open(Uri uri) { try { systemDownload(context1, FileUtils.getFileNameFromUrl(url), uri.toString()); if (finish) context1.finish(); } catch (Throwable e) { AppLog.e(context1, e); } } }) .execute(url); break; case "2": new GetTempUrlTask(context1, new GetTempUrlTask.onOpenUrlInterface() { @Override public void open(Uri uri) { try { Intent marketIntent = new Intent(Intent.ACTION_VIEW, uri); context1.startActivity(marketIntent); if (finish) context1.finish(); } catch (Throwable e) { AppLog.e(context1, e); } } }) .execute(url); break; } } catch (Throwable ex) { AppLog.e(context1, ex); } } }, context1.getString(R.string.download_method_notify) ); } private static void systemDownload(Context context, String fileName, String url) throws IOException { DownloadManager dm = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); List<Cookie> cookies = Client.getInstance().getCookies(); StringBuilder sb = new StringBuilder(); for (Cookie cookie : cookies) { sb.append(cookie.getName() + "=" + cookie.getValue() + ";"); } request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.addRequestHeader("Cookie", sb.toString()); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); dm.enqueue(request); } private static void clientDownload(final Context context1, final String url, String tempFilePath, final int notificationId) throws UnsupportedEncodingException { final String fileName = FileUtils.getFileNameFromUrl(url); if (TextUtils.isEmpty(tempFilePath)) { final String filePath = FileUtils.combine(DownloadsService.getDownloadDir(context1), FileUtils.getFileNameFromUrl(url) + "_download"); final File file = new File(filePath); if (file.exists()) { new MaterialDialog.Builder(context1) .title(R.string.attention) .content(R.string.ask_file_need_download) .positiveText(R.string.continue_download) .negativeText(R.string.re_download) .callback(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog dialog) { startDownload(context1, url, filePath, notificationId, fileName); } @Override public void onNegative(MaterialDialog dialog) { startDownload(context1, url, null, notificationId, fileName); } }).show(); return; } } startDownload(context1, url, tempFilePath, notificationId, fileName); } private static void startDownload(Context context1, String url, String tempFilePath, int notificationId, String fileName) { try { Toast.makeText(context1, R.string.download_started, Toast.LENGTH_SHORT).show(); if (notificationId == -1) notificationId = DownloadsTable.getNextId(); DownloadReceiver.showProgressNotification(context1, notificationId, fileName, 0, url); Client.getInstance().downloadFile(context1, url, notificationId, tempFilePath); } catch (Exception ex) { AppLog.e(context1, ex); } } public void downloadFile(ResultReceiver receiver, int notificationId, String tempFilePath) { DownloadTask downloadTask = null; try { String dirPath = getDownloadDir(getApplicationContext()); downloadTask = Client.getInstance().getDownloadTasks().getById(notificationId); if (downloadTask.getState() == DownloadTask.STATE_CANCELED) { return; } String url = downloadTask.getUrl(); url = FileUtils.getDirPath(url) + "/" + URLEncoder.encode(FileUtils.getFileNameFromUrl(url)); HttpHelper httpHelper = new HttpHelper(); try { String fileName = TextUtils.isEmpty(tempFilePath) ? FileUtils.getFileNameFromUrl(url) : FileUtils.getFileNameFromUrl(tempFilePath.replace("_download", "")); String saveDir = dirPath; String filePath = TextUtils.isEmpty(tempFilePath) ? FileUtils.getUniqueFilePath(saveDir, fileName) : FileUtils.combine(saveDir, fileName); downloadTask.setOutputFile(filePath); String downloadingFilePath = filePath + "_download"; downloadTask.setDownloadingFilePath(downloadingFilePath); FileUtils.mkDirs(downloadingFilePath); // new File(downloadingFilePath).createNewFile(); long total = TextUtils.isEmpty(tempFilePath) ? 0 : DownloadTask.getRange(tempFilePath); url = FileUtils.getDirPath(url) + "/" + URLEncoder.encode(FileUtils.getFileNameFromUrl(url)); HttpEntity entity = httpHelper.getDownloadEntity(url, total); long fileLength = entity.getContentLength() + total; downloadTask.updateInfo(fileLength); downloadTask.setProgressState(total, fileLength); sendDownloadProgressState(receiver, notificationId); int count; int percent = 0; int prevPercent = 0; Date lastUpdateTime = new Date(); Boolean first = true; // for test InputStream in = entity.getContent(); FileOutputStream output = new FileOutputStream(downloadingFilePath, true); byte data[] = new byte[BUFFER_SIZE]; try { while ((count = in.read(data)) != -1) { if (downloadTask.getState() == DownloadTask.STATE_CANCELED) { sendDownloadProgressState(receiver, notificationId); return; } output.write(data, 0, count); total += count; percent = (int) ((float) total / fileLength * 100); long diffInMs = new Date().getTime() - lastUpdateTime.getTime(); long diffInSec = TimeUnit.MILLISECONDS.toSeconds(diffInMs); if ((percent != prevPercent && diffInSec > 1) || first) { lastUpdateTime = new Date(); downloadTask.setProgressState(total, fileLength); sendDownloadProgressState(receiver, notificationId); first = false; } prevPercent = percent; } downloadTask.setProgressState(fileLength, fileLength); sendDownloadProgressState(receiver, notificationId); } finally { output.flush(); output.close(); in.close(); } File downloadingFile = new File(downloadingFilePath); File downloadedFile = new File(filePath); if (!downloadingFile.renameTo(downloadedFile)) { throw new NotReportException(App.getContext().getString(R.string.rename_file_exception) + downloadingFilePath +App.getContext().getString(R.string.combined_in) + filePath); } downloadTask.setState(downloadTask.STATE_SUCCESSFULL); sendDownloadProgressState(receiver, notificationId); DownloadsTable.endRow(downloadTask); } finally { httpHelper.close(); } } catch (Exception ex) { if (downloadTask != null) { downloadTask.setEx(ex); downloadTask.setState(downloadTask.STATE_ERROR); DownloadsTable.endRow(downloadTask); sendDownloadProgressState(receiver, notificationId); } ex.printStackTrace(); } } public static void sendDownloadProgressState(ResultReceiver receiver, int downloadTaskId) { Bundle resultData = new Bundle(); resultData.putInt("downloadTaskId", downloadTaskId); receiver.send(UPDATE_PROGRESS, resultData); } private static class GetTempUrlTask extends AsyncTask<String, Void, Uri> { private final MaterialDialog dialog; private Context m_Context; private onOpenUrlInterface openUrlAction; public interface onOpenUrlInterface { void open(Uri uri); } public GetTempUrlTask(Context context, onOpenUrlInterface openUrlAction) { m_Context = context; this.openUrlAction = openUrlAction; dialog = new MaterialDialog.Builder(context) .progress(true,0) .content(R.string.request_link) .build(); } @Override protected Uri doInBackground(String... params) { HttpHelper httpHelper = null; try { httpHelper = new HttpHelper(); String url = params[0]; httpHelper.getDownloadResponse(url, 0); URI redirectUri = HttpHelper.getRedirectUri(); Uri uri = Uri.parse(url); if (redirectUri != null) uri = Uri.parse(redirectUri.toString()); return uri; } catch (Throwable e) { ex = e; return null; } finally { if (httpHelper != null) httpHelper.close(); } } // can use UI thread here protected void onPreExecute() { try { this.dialog.show(); } catch (Throwable ignored) { } } private Throwable ex; // can use UI thread here protected void onPostExecute(final Uri uri) { try { if (this.dialog.isShowing()) { this.dialog.dismiss(); } } catch (Throwable ignored) { } if (uri != null) { openUrlAction.open(uri); } else { if (ex != null) AppLog.e(m_Context, ex); else Toast.makeText(m_Context, R.string.unknown_error, Toast.LENGTH_SHORT).show(); } } } }