package com.golshadi.majid.core; import android.app.Activity; import android.content.Context; import android.os.Environment; import android.util.Log; import com.example.test.MyActivity; import com.golshadi.majid.Utils.helper.FileUtils; import com.golshadi.majid.core.chunkWorker.Moderator; import com.golshadi.majid.core.enums.QueueSort; import com.golshadi.majid.core.enums.TaskStates; import com.golshadi.majid.core.mainWorker.AsyncStartDownload; import com.golshadi.majid.core.mainWorker.QueueModerator; import com.golshadi.majid.database.ChunksDataSource; import com.golshadi.majid.database.DatabaseHelper; import com.golshadi.majid.database.TasksDataSource; import com.golshadi.majid.database.elements.Chunk; import com.golshadi.majid.database.elements.Task; import com.golshadi.majid.report.ReportStructure; import com.golshadi.majid.report.exceptions.QueueDownloadInProgressException; import com.golshadi.majid.report.exceptions.QueueDownloadNotStartedException; import com.golshadi.majid.report.listener.DownloadManagerListener; import com.golshadi.majid.report.listener.DownloadManagerListenerModerator; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Created by Majid Golshadi on 4/10/2014. */ public class DownloadManagerPro { private final int MAX_CHUNKS = 16; static String SAVE_FILE_FOLDER = null; static int maximumUserChunks; private Moderator moderator; private DatabaseHelper dbHelper; private TasksDataSource tasksDataSource; private ChunksDataSource chunksDataSource; private DownloadManagerListenerModerator downloadManagerListener; private QueueModerator qt; /** * <p> * Download manager pro Object constructor *</p> * * @param context */ public DownloadManagerPro(Context context){ dbHelper = new DatabaseHelper(context); // dbHelper.close(); // ready database data source to access tables tasksDataSource = new TasksDataSource(); tasksDataSource.openDatabase(dbHelper); chunksDataSource = new ChunksDataSource(); chunksDataSource.openDatabase(dbHelper); // moderate chunks to download one task moderator = new Moderator(tasksDataSource, chunksDataSource); } /** * <p> * i don't want to force developer to init download manager * so i can't get downloadManagerListener at constructor but that way seems better than now * </p> * @param sdCardFolderAddress * @param maxChunks * @param listener */ public void init(String sdCardFolderAddress, int maxChunks, DownloadManagerListener listener){ // ready folder to save download content in it File saveFolder = new File(Environment.getExternalStorageDirectory(), sdCardFolderAddress); if (!saveFolder.exists()) saveFolder.mkdirs(); SAVE_FILE_FOLDER = saveFolder.getPath().toString(); maximumUserChunks = setMaxChunk(maxChunks); downloadManagerListener = new DownloadManagerListenerModerator(listener); } /** * <p> * add a new download Task * </p> * * @param saveName * file name * @param url * url file address * @param chunk * number of chunks * @param sdCardFolderAddress * downloaded file save address * @param overwrite * if exist an other file with same name * "true" over write that file * "false" find new name and save it with new name * * @return id * inserted task id */ public int addTask(String saveName, String url, int chunk, String sdCardFolderAddress, boolean overwrite, boolean priority){ if ( ! overwrite ) saveName = getUniqueName(saveName); else deleteSameDownloadNameTask(saveName); Log.d("--------", "overwrite"); chunk = setMaxChunk(chunk); Log.d("--------", "ma chunk"); return insertNewTask(saveName, url, chunk, sdCardFolderAddress, priority); } public int addTask(String saveName, String url, int chunk, boolean overwrite, boolean priority){ return this.addTask(saveName, url, chunk, SAVE_FILE_FOLDER, overwrite, priority); } public int addTask(String saveName, String url, boolean overwrite, boolean priority) { return this.addTask(saveName, url, maximumUserChunks, SAVE_FILE_FOLDER, overwrite, priority); } /** *<p> * first of all check task state and depend on start download process from where ever need *</p> * * @param token * now token is download task id * @throws java.io.IOException */ public void startDownload(int token) throws IOException { // switch on task state Log.d("--------", "task state"); Task task = tasksDataSource.getTaskInfo(token); Log.d("--------", "task state 1"); Thread asyncStartDownload = new AsyncStartDownload(tasksDataSource, chunksDataSource, moderator, downloadManagerListener, task); Log.d("--------", "define async download"); asyncStartDownload.start(); Log.d("--------", "define async download started"); } /** * @param downloadTaskPerTime */ public void startQueueDownload(int downloadTaskPerTime, int sortType) throws QueueDownloadInProgressException { Moderator localModerator = new Moderator(tasksDataSource, chunksDataSource); List<Task> unCompletedTasks = tasksDataSource.getUnCompletedTasks(sortType); if (qt == null) { qt = new QueueModerator(tasksDataSource, chunksDataSource, localModerator, downloadManagerListener, unCompletedTasks, downloadTaskPerTime); qt.startQueue(); } else { throw new QueueDownloadInProgressException(); } } /** * <p> * pause separate download task * </p> * * @param token */ public void pauseDownload(int token) { moderator.pause(token); } /** * pause queue download * @throws com.golshadi.majid.report.exceptions.QueueDownloadNotStartedException */ public void pauseQueueDownload() throws QueueDownloadNotStartedException { if (qt != null) { qt.pause(); qt = null; } else { throw new QueueDownloadNotStartedException(); } } //-----------Reports /** * report task download status in "ReportStructure" style * * @param token * when you add a new download task it's return to you * @return */ public ReportStructure singleDownloadStatus(int token) { ReportStructure report = new ReportStructure(); Task task = tasksDataSource.getTaskInfo(token); if (task != null) { List<Chunk> taskChunks = chunksDataSource.chunksRelatedTask(task.id); report.setObjectValues(task, taskChunks); return report; } return null; } /** * <p> * it's an report method for * return list of download task in same state that developer want as ReportStructure List object * </p> * @param state * 0. get all downloads Status * 1. init * 2. ready * 3. downloading * 4. paused * 5. download finished * 6. end * @return */ public List<ReportStructure> downloadTasksInSameState(int state){ List<ReportStructure> reportList; List<Task> inStateTasks = tasksDataSource.getTasksInState(state); reportList = readyTaskList(inStateTasks); return reportList; } /** * return list of last completed Download tasks in "ReportStructure" style * you can use it as notifier * * @return */ public List<ReportStructure> lastCompletedDownloads(){ List<ReportStructure> reportList = new ArrayList<ReportStructure>(); List<Task> lastCompleted = tasksDataSource.getUnnotifiedCompleted(); reportList = readyTaskList(lastCompleted); return reportList; } private List<ReportStructure> readyTaskList(List<Task> tasks){ List<ReportStructure> reportList = new ArrayList<ReportStructure>(); for (Task task : tasks){ List<Chunk> taskChunks = chunksDataSource.chunksRelatedTask(task.id); ReportStructure singleReport = new ReportStructure(); singleReport.setObjectValues(task, taskChunks); reportList.add(singleReport); } return reportList; } /** * <p> * check all notified tasks * so in another "lastCompletedDownloads" call ,completed task does not show again * * persian: * "lastCompletedDownloads" list akharin task haii ke takmil shodeand ra namayesh midahad * ba seda zadan in method tamami task haii ke dar gozaresh e ghabli elam shode boodand ra * az liste "lastCompeletedDownloads" hazf mikonad * * !!!SHIT!!! * </p> * * @return * true or false */ public boolean notifiedTaskChecked(){ return tasksDataSource.checkUnNotifiedTasks(); } /** * delete download task from db and if you set deleteTaskFile as true * it's go to saved folder and delete that file * * @param token * when you add a new download task it's return to you * @param deleteTaskFile * delete completed download file from sd card if you set it true * @return * "true" if anything goes right * "false" if something goes wrong */ public boolean delete(int token, boolean deleteTaskFile){ Task task = tasksDataSource.getTaskInfo(token); if (task.url != null){ List<Chunk> taskChunks = chunksDataSource.chunksRelatedTask(task.id); for (Chunk chunk : taskChunks) { FileUtils.delete(task.save_address, String.valueOf(chunk.id)); chunksDataSource.delete(chunk.id); } if (deleteTaskFile) { long size = FileUtils.size(task.save_address, task.name + "." + task.extension); if (size > 0){ FileUtils.delete(task.save_address, task.name + "." + task.extension); } } return tasksDataSource.delete(task.id); } return false; } /** * close db connection * if your activity goes to paused or stop state * you have to call this method to disconnect from db */ public void dispose(){ dbHelper.close(); } private List<Task> uncompleted(){ return tasksDataSource.getUnCompletedTasks(QueueSort.oldestFirst); } private int insertNewTask(String taskName, String url, int chunk, String save_address, boolean priority) { Task task = new Task(0, taskName, url, TaskStates.INIT, chunk, save_address, priority); task.id = (int) tasksDataSource.insertTask(task); Log.d("--------", "task id "+String.valueOf(task.id)); return task.id; } private int setMaxChunk(int chunk){ if (chunk < MAX_CHUNKS) return chunk; return MAX_CHUNKS; } private String getUniqueName(String name){ String uniqueName = name; int count = 0; while ( isDuplicatedName(uniqueName) ){ uniqueName = name+"_"+count; count++; } return uniqueName; } private boolean isDuplicatedName(String name){ return tasksDataSource.containsTask( name ); } /* valid values are INIT = 0; READY = 1; DOWNLOADING = 2; PAUSED = 3; DOWNLOAD_FINISHED = 4; END = 5; so if his token was wrong return -1 */ private void deleteSameDownloadNameTask(String saveName){ if (isDuplicatedName(saveName)){ Task task = tasksDataSource.getTaskInfoWithName(saveName); tasksDataSource.delete(task.id); FileUtils.delete(task.save_address, task.name + "." + task.extension); } } }