diff --git a/.gitignore b/.gitignore index f368eb2eb..ce17b7ee4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *~ +classes *# bin gen diff --git a/res/values/strings.xml b/res/values/strings.xml index 1e8ace3b7..77257e79c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -305,4 +305,6 @@ Cancel all Download List Upload List + All files has been downloaded + Starting to download %d files diff --git a/src/com/seafile/seadroid2/cameraupload/CameraUploadService.java b/src/com/seafile/seadroid2/cameraupload/CameraUploadService.java index dd3a8c0d6..d554dd576 100644 --- a/src/com/seafile/seadroid2/cameraupload/CameraUploadService.java +++ b/src/com/seafile/seadroid2/cameraupload/CameraUploadService.java @@ -28,10 +28,8 @@ import com.seafile.seadroid2.SettingsManager; import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.data.SeafCachedPhoto; -import com.seafile.seadroid2.transfer.PendingUploadInfo; -import com.seafile.seadroid2.transfer.TransferService; +import com.seafile.seadroid2.transfer.*; import com.seafile.seadroid2.transfer.TransferService.TransferBinder; -import com.seafile.seadroid2.transfer.UploadTaskInfo; import com.seafile.seadroid2.util.CameraUploadUtil; public class CameraUploadService extends Service { @@ -75,13 +73,13 @@ public void onCreate() { MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, cameraUploadObserver); LocalBroadcastManager.getInstance(this).registerReceiver(transferReceiver, - new IntentFilter(TransferService.BROADCAST_ACTION)); + new IntentFilter(TransferManager.BROADCAST_ACTION)); } private void cancelUploadTasks(){ mTransferService.cancelAllCameraUploadTasks(); - Intent localIntent = new Intent(TransferService.BROADCAST_ACTION).putExtra("type", + Intent localIntent = new Intent(TransferManager.BROADCAST_ACTION).putExtra("type", BROADCAST_CAMERA_UPLOAD_SERVICE_STOPPED); LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(localIntent); } @@ -241,7 +239,7 @@ protected void onPostExecute(List result) { // do nothing until network connection available } if (isNetworkAvailable && !isRemoteCameraUploadRepoValid) { - localIntent = new Intent(TransferService.BROADCAST_ACTION).putExtra("type", + localIntent = new Intent(TransferManager.BROADCAST_ACTION).putExtra("type", BROADCAST_CAMERA_UPLOAD_LIBRARY_NOT_FOUND); LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(localIntent); } @@ -295,7 +293,7 @@ public void onReceive(Context context, Intent intent) { } List list = Lists.newArrayList(); - if (type.equals(TransferService.BROADCAST_FILE_UPLOAD_SUCCESS)) { + if (type.equals(UploadTaskManager.BROADCAST_FILE_UPLOAD_SUCCESS)) { int taskID = intent.getIntExtra("taskID", 0); UploadTaskInfo info = mTransferService.getUploadTaskInfo(taskID); diff --git a/src/com/seafile/seadroid2/monitor/FileMonitorService.java b/src/com/seafile/seadroid2/monitor/FileMonitorService.java index 334a6f6ef..9110d2429 100644 --- a/src/com/seafile/seadroid2/monitor/FileMonitorService.java +++ b/src/com/seafile/seadroid2/monitor/FileMonitorService.java @@ -14,9 +14,7 @@ import com.seafile.seadroid2.ConcurrentAsyncTask; import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.transfer.DownloadTaskInfo; -import com.seafile.seadroid2.transfer.TransferService; -import com.seafile.seadroid2.transfer.UploadTaskInfo; +import com.seafile.seadroid2.transfer.*; /** * Monitor changes of local cached files, and upload them through TransferService if modified @@ -67,7 +65,7 @@ public void onCreate() { bindService(bindIntent, mTransferConnection, Context.BIND_AUTO_CREATE); LocalBroadcastManager.getInstance(this).registerReceiver(transferReceiver, - new IntentFilter(TransferService.BROADCAST_ACTION)); + new IntentFilter(TransferManager.BROADCAST_ACTION)); } @Override @@ -126,7 +124,7 @@ public void onReceive(Context context, Intent intent) { return; } - if (type.equals(TransferService.BROADCAST_FILE_DOWNLOAD_SUCCESS)) { + if (type.equals(DownloadTaskManager.BROADCAST_FILE_DOWNLOAD_SUCCESS)) { int taskID = intent.getIntExtra("taskID", 0); DownloadTaskInfo info = mTransferService.getDownloadTaskInfo(taskID); if (info != null) { @@ -135,7 +133,7 @@ public void onReceive(Context context, Intent intent) { info.pathInRepo, info.localFilePath); } } - } else if (type.equals(TransferService.BROADCAST_FILE_UPLOAD_SUCCESS)) { + } else if (type.equals(UploadTaskManager.BROADCAST_FILE_UPLOAD_SUCCESS)) { int taskID = intent.getIntExtra("taskID", 0); UploadTaskInfo info = mTransferService.getUploadTaskInfo(taskID); @@ -143,7 +141,7 @@ public void onReceive(Context context, Intent intent) { updateMgr.onFileUpdateSuccess(info.account, info.repoID, info.repoName, info.parentDir, info.localFilePath); } - } else if (type.equals(TransferService.BROADCAST_FILE_UPLOAD_FAILED)) { + } else if (type.equals(UploadTaskManager.BROADCAST_FILE_UPLOAD_FAILED)) { int taskID = intent.getIntExtra("taskID", 0); UploadTaskInfo info = mTransferService.getUploadTaskInfo(taskID); diff --git a/src/com/seafile/seadroid2/transfer/DownloadStateListener.java b/src/com/seafile/seadroid2/transfer/DownloadStateListener.java new file mode 100644 index 000000000..ae77e237e --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/DownloadStateListener.java @@ -0,0 +1,12 @@ +package com.seafile.seadroid2.transfer; + +/** + * Download state listener + * + * Created by Logan on 15/2/7. + */ +public interface DownloadStateListener { + void onFileDownloadProgress(int taskID); + void onFileDownloaded(int taskID); + void onFileDownloadFailed(int taskID); +} diff --git a/src/com/seafile/seadroid2/transfer/DownloadTask.java b/src/com/seafile/seadroid2/transfer/DownloadTask.java new file mode 100644 index 000000000..ea71ec8b6 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/DownloadTask.java @@ -0,0 +1,96 @@ +package com.seafile.seadroid2.transfer; + +import com.seafile.seadroid2.SeafException; +import com.seafile.seadroid2.account.Account; +import com.seafile.seadroid2.data.DataManager; +import com.seafile.seadroid2.data.ProgressMonitor; + +import java.io.File; + +/** + * Download task + * + * Created by Logan on 15/2/3. + */ +public class DownloadTask extends TransferTask { + + private String localPath; + private DownloadStateListener downloadStateListener; + + public DownloadTask(int taskID, Account account, String repoName, String repoID, String path, + DownloadStateListener downloadStateListener) { + super(taskID, account, repoName, repoID, path); + this.downloadStateListener = downloadStateListener; + } + + /** + * When downloading a file, we don't know the file size in advance, so + * we make use of the first progress update to return the file size. + */ + @Override + protected void onProgressUpdate(Long... values) { + if (totalSize == -1) { + totalSize = values[0]; + state = TaskState.TRANSFERRING; + return; + } + finished = values[0]; + downloadStateListener.onFileDownloadProgress(taskID); + } + + @Override + protected File doInBackground(Void... params) { + try { + DataManager dataManager = new DataManager(account); + return dataManager.getFile(repoName, repoID, path, + new ProgressMonitor() { + + @Override + public void onProgressNotify(long total) { + publishProgress(total); + } + + @Override + public boolean isCancelled() { + return DownloadTask.this.isCancelled(); + } + } + ); + } catch (SeafException e) { + err = e; + return null; + } + } + + @Override + protected void onPostExecute(File file) { + if (downloadStateListener != null) { + if (file != null) { + state = TaskState.FINISHED; + localPath = file.getPath(); + downloadStateListener.onFileDownloaded(taskID); + } else { + state = TaskState.FAILED; + if (err == null) + err = SeafException.unknownException; + downloadStateListener.onFileDownloadFailed(taskID); + } + } + } + + @Override + protected void onCancelled() { + state = TaskState.CANCELLED; + } + + @Override + public DownloadTaskInfo getTaskInfo() { + DownloadTaskInfo info = new DownloadTaskInfo(account, taskID, state, repoID, + repoName, path, localPath, totalSize, finished, err); + return info; + } + + public String getLocalPath() { + return localPath; + } +} \ No newline at end of file diff --git a/src/com/seafile/seadroid2/transfer/DownloadTaskInfo.java b/src/com/seafile/seadroid2/transfer/DownloadTaskInfo.java index a4aca5aa3..2f03619fe 100644 --- a/src/com/seafile/seadroid2/transfer/DownloadTaskInfo.java +++ b/src/com/seafile/seadroid2/transfer/DownloadTaskInfo.java @@ -2,8 +2,9 @@ import com.seafile.seadroid2.SeafException; import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.transfer.TransferManager.TaskState; - +/** + * download task info + */ public class DownloadTaskInfo extends TransferTaskInfo { public final String pathInRepo; diff --git a/src/com/seafile/seadroid2/transfer/DownloadTaskManager.java b/src/com/seafile/seadroid2/transfer/DownloadTaskManager.java new file mode 100644 index 000000000..7e1ce9ea5 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/DownloadTaskManager.java @@ -0,0 +1,126 @@ +package com.seafile.seadroid2.transfer; + +import android.content.Intent; +import android.support.v4.content.LocalBroadcastManager; +import com.google.common.collect.Lists; +import com.seafile.seadroid2.ConcurrentAsyncTask; +import com.seafile.seadroid2.SeadroidApplication; +import com.seafile.seadroid2.account.Account; +import com.seafile.seadroid2.util.Utils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Download task manager + *

+ * Created by Logan on 15/2/4. + */ +public class DownloadTaskManager extends TransferManager implements DownloadStateListener { + private static final String DEBUG_TAG = "DownloadTaskManager"; + + public static final String BROADCAST_FILE_DOWNLOAD_SUCCESS = "downloaded"; + public static final String BROADCAST_FILE_DOWNLOAD_FAILED = "downloadFailed"; + public static final String BROADCAST_FILE_DOWNLOAD_PROGRESS = "downloadProgress"; + + /** + * Add a new download task. + * call this method to execute a task immediately. + */ + public int addTask(Account account, String repoName, String repoID, String path) { + TransferTask task = new DownloadTask(++notificationID, account, + repoName, repoID, path, this); + if (allTaskList.contains(task)) { + if (task.getState().equals(TaskState.CANCELLED) + || task.getState().equals(TaskState.FAILED) + || task.getState().equals(TaskState.FINISHED)) { + allTaskList.remove(task); + } else { + // return taskID of old task + return allTaskList.get(allTaskList.indexOf(task)).getTaskID(); + } + } + allTaskList.add(task); + ConcurrentAsyncTask.execute(task); + return task.getTaskID(); + } + + public void addTaskToQue(Account account, String repoName, String repoID, String path) { + // create a new one to avoid IllegalStateException + DownloadTask downloadTask = new DownloadTask(++notificationID, account, repoName, repoID, path, this); + addTaskToQue(downloadTask); + } + + public int getDownloadingFileCountByPath(String repoID, String dir) { + List downloadTaskInfos = getTaskInfoListByPath(repoID, dir); + int count = 0; + for (DownloadTaskInfo downloadTaskInfo : downloadTaskInfos) { + if (downloadTaskInfo.state.equals(TaskState.INIT) + || downloadTaskInfo.state.equals(TaskState.TRANSFERRING)) + count++; + } + return count; + } + + /** + * get all download task info under a specific directory. + * + * @param repoID + * @param dir valid dir should be something like this "/DIRNAME/", instead of "/DIRNAME", + * in order to ensure the param being consistent with its caller + * @return List + */ + public List getTaskInfoListByPath(String repoID, String dir) { + ArrayList infos = Lists.newArrayList(); + for (TransferTask task : allTaskList) { + if (!task.getRepoID().equals(repoID)) + continue; + + String parentDir = Utils.getParentPath(task.getPath()); + String validDir; + + if (!parentDir.equals("/")) + validDir = parentDir + "/"; + else + validDir = parentDir; + + if (validDir.equals(dir)) + infos.add(((DownloadTask) task).getTaskInfo()); + } + + return infos; + } + + public void retry(int taskID) { + DownloadTask task = (DownloadTask) getTask(taskID); + if (task == null || !task.canRetry()) + return; + addTaskToQue(task.getAccount(), task.getRepoName(), task.getRepoID(), task.getPath()); + } + + // -------------------------- listener method --------------------// + @Override + public void onFileDownloadProgress(int taskID) { + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_DOWNLOAD_PROGRESS).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } + + @Override + public void onFileDownloaded(int taskID) { + remove(taskID); + doNext(); + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_DOWNLOAD_SUCCESS).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } + + @Override + public void onFileDownloadFailed(int taskID) { + remove(taskID); + doNext(); + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_DOWNLOAD_FAILED).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } +} diff --git a/src/com/seafile/seadroid2/transfer/TaskState.java b/src/com/seafile/seadroid2/transfer/TaskState.java new file mode 100644 index 000000000..7f28465f7 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/TaskState.java @@ -0,0 +1,8 @@ +package com.seafile.seadroid2.transfer; + +/** + * Task state + * + * Created by Logan on 15/2/3. + */ +public enum TaskState { INIT, TRANSFERRING, FINISHED, CANCELLED, TaskState, FAILED } diff --git a/src/com/seafile/seadroid2/transfer/TransferManager.java b/src/com/seafile/seadroid2/transfer/TransferManager.java index 14174fa29..73a9e9062 100644 --- a/src/com/seafile/seadroid2/transfer/TransferManager.java +++ b/src/com/seafile/seadroid2/transfer/TransferManager.java @@ -1,353 +1,44 @@ package com.seafile.seadroid2.transfer; -import android.os.AsyncTask; import android.util.Log; import com.google.common.collect.Lists; import com.seafile.seadroid2.ConcurrentAsyncTask; -import com.seafile.seadroid2.SeafException; -import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.data.DataManager; -import com.seafile.seadroid2.data.ProgressMonitor; -import com.seafile.seadroid2.util.Utils; -import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Manages file downloading and uploading. - * + *

* Currently use an AsyncTask for an file. */ -public class TransferManager { +public abstract class TransferManager { private static final String DEBUG_TAG = "TransferManager"; - public enum TaskState { INIT, TRANSFERRING, FINISHED, CANCELLED, FAILED } - - public interface TransferListener { - void onFileUploadProgress(int taskID); - void onFileUploaded(int taskID); - void onFileUploadCancelled(int taskID); - void onFileUploadFailed(int taskID); - - void onFileDownloadProgress(int taskID); - void onFileDownloaded(int taskID); - void onFileDownloadFailed(int taskID); - } - - private ArrayList uploadTasks; - private ArrayList downloadTasks; - private int notificationID; - TransferListener listener; - - private List uploadWaitingList = Lists.newArrayList(); - private List uploadingList = Lists.newArrayList(); - private static final int UPLOAD_MAX_COUNT = 2; - - private List downloadingList = Lists.newArrayList(); - private List downloadWaitingList = Lists.newArrayList(); - private static final int DOWNLOAD_MAX_COUNT = 2; - - public TransferManager() { - notificationID = 0; - uploadTasks = Lists.newArrayList(); - downloadTasks = Lists.newArrayList(); - listener = null; - } - - public void setListener(TransferListener listener) { - this.listener = listener; - } - - public void unsetListener() { - listener = null; - } + public static final String BROADCAST_ACTION = "com.seafile.seadroid.TX_BROADCAST"; /** - * Add a new upload task - * this method is deprecated. + * unique task id */ - public int addUploadTask(Account account, String repoID, String repoName, - String dir, String filePath, boolean isUpdate, boolean isCopyToLocal) { - Iterator iter = uploadTasks.iterator(); - - while (iter.hasNext()) { - UploadTask task = iter.next(); - if (task.myRepoID.equals(repoID) && task.myPath.equals(filePath)) { - if (task.myState == TaskState.CANCELLED || task.myState == TaskState.FAILED - || task.myState == TaskState.FINISHED) { - // If there is a duplicate, but it has failed or been - // cancelled, remove it first - iter.remove(); - break; - } else { - // A duplicate task is uploading - return task.getTaskID(); - } - } - } - - UploadTask task = new UploadTask(account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal); - task.execute(); - return task.getTaskID(); - } - + protected int notificationID; + protected static final int TRANSFER_MAX_COUNT = 2; /** - * add upload task to queue - * @param account - * @param repoID - * @param repoName - * @param dir - * @param filePath - * @param isUpdate - * @param isCopyToLocal + * contains all transfer tasks, including failed, cancelled, finished, transferring, waiting tasks. */ - public int addTaskToUploadQue(Account account, - String repoID, - String repoName, - String dir, - String filePath, - boolean isUpdate, - boolean isCopyToLocal) { - - int taskID = -1; - synchronized (uploadWaitingList) { - boolean hasInQue = false; - for (UploadTask uploadTask : uploadWaitingList) { - if (uploadTask.myPath.equals(filePath)) { - hasInQue = true; - taskID = uploadTask.getTaskID(); - // Log.d(DEBUG_TAG, "in Que " + index + " " + filePath + "in waiting list"); - break; - } - } - - for (UploadTask uploadTask : uploadingList) { - if (uploadTask.myPath.equals(filePath)) { - hasInQue = true; - taskID = uploadTask.getTaskID(); - // Log.d(DEBUG_TAG, "in Que " + index + " " + filePath + "in uploading list"); - break; - } - } - - if (!hasInQue) { - UploadTask task = new UploadTask(account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal); - // Log.d(DEBUG_TAG, "add Que " + task.getTaskID() + " " + filePath); - taskID = task.getTaskID(); - - uploadWaitingList.add(task); - - uploadNext(); - } - } - return taskID; - } - - private void uploadNextInQue(int taskID) { - synchronized (uploadWaitingList) { - removeCurrentUploadItem(taskID); - uploadNext(); - } - } - - public void uploadNext() { - // Log.d(DEBUG_TAG, "UploadingCount:" + uploadingList.size()); - if (!uploadWaitingList.isEmpty() - && uploadingList.size() < UPLOAD_MAX_COUNT) { - // Log.d(DEBUG_TAG, "do next!"); - - UploadTask item = uploadWaitingList.get(0); - uploadingList.add(item); - uploadWaitingList.remove(0); - ConcurrentAsyncTask.execute(item); - } - } - - private void removeCurrentUploadItem(int taskID) { - // Log.d(DEBUG_TAG, "removeCurrentUploadItem:" + taskID); - if (!uploadingList.isEmpty()) { - UploadTask toRemove = getUploadTaskByID(taskID); - for (int i = 0; i < uploadingList.size(); i++) { - if (uploadingList.get(i).myPath.equals(toRemove.myPath)) { - // Log.d(DEBUG_TAG, "Done Que " + taskID + " " + uploadingList.get(i).myPath); - uploadingList.remove(i); - break; - } - } - } - - } - + protected List allTaskList = Lists.newArrayList(); /** - * Add a new download task - * this method is deprecated. + * contains currently transferring tasks */ - public int addDownloadTask(Account account, - String repoName, - String repoID, - String path) { - Iterator iter = downloadTasks.iterator(); - while (iter.hasNext()) { - DownloadTask task = iter.next(); - if (task.myRepoID.equals(repoID) && task.myPath.equals(path)) { - if (task.myState == TaskState.CANCELLED || task.myState == TaskState.FAILED - || task.myState == TaskState.FINISHED) { - // If there is a duplicate, but it has failed or been - // cancelled, remove it first - iter.remove(); - break; - } else { - // A duplicate task is downloading - return task.getTaskID(); - } - } - } - - DownloadTask task = new DownloadTask(account, repoName, repoID, path); - task.execute(); - return task.getTaskID(); - } - - public int addTaskToDownloadQue(Account account, - String repoName, - String repoID, - String path) { - int taskID = -1; - synchronized (downloadWaitingList) { - boolean hasInQue = false; - for (DownloadTask downloadTask : downloadWaitingList) { - if (downloadTask.myRepoName.equals(repoName) && - downloadTask.myPath.equals(path)) { - hasInQue = true; - taskID = downloadTask.getTaskID(); - // Log.d(DEBUG_TAG, "in Que " + index + " " + repoName + path + "in waiting list"); - break; - } - } - - for (DownloadTask downloadTask : downloadingList) { - if (downloadTask.myRepoName.equals(repoName) && - downloadTask.myPath.equals(path)) { - hasInQue = true; - taskID = downloadTask.getTaskID(); - // Log.d(DEBUG_TAG, "in Que " + index + " " + repoName + path + " in downloading list" ); - break; - } - } - - if (!hasInQue) { - DownloadTask task = new DownloadTask(account, repoName, repoID, path); - - taskID = task.getTaskID(); - // Log.d(DEBUG_TAG, "add Que " + task.getTaskID() + " " + repoName + path); - downloadWaitingList.add(task); - downloadNext(); - } - } - return taskID; - } - - public void downloadNext() { - // Log.d(DEBUG_TAG, "DownloadingCount:" + downloadWaitingList.size()); - if (!downloadWaitingList.isEmpty() - && downloadingList.size() < DOWNLOAD_MAX_COUNT) { - // Log.d(DEBUG_TAG, "do next!"); - - DownloadTask item = downloadWaitingList.get(0); - downloadingList.add(item); - downloadWaitingList.remove(0); - ConcurrentAsyncTask.execute(item); - } - } - - private void downloadNextInQue(int taskID) { - synchronized (downloadWaitingList) { - removeCurrentDownloadItem(taskID); - downloadNext(); - } - } - - private void removeCurrentDownloadItem(int taskID) { - // Log.d(DEBUG_TAG, "removeCurrentDownloadItem:" + taskID); - - if (!downloadingList.isEmpty()) { - DownloadTask toRemove = getDownloadTaskByID(taskID); - for (int i = 0; i < downloadingList.size(); i++) { - if (downloadingList.get(i).myRepoName.equals(toRemove.myRepoName) && - downloadingList.get(i).myPath.equals(toRemove.myPath)) { - // Log.d(DEBUG_TAG, "Done Que " + taskID + " " + toRemove.myRepoName + toRemove.myPath); - downloadingList.remove(i); - break; - } - } - } - - } - - public void removeCancelledDownloadItemInQue(int taskID) { - - synchronized (downloadWaitingList) { - - DownloadTask toCancel = getDownloadTaskByID(taskID); - if (!downloadWaitingList.isEmpty()) { - for (int i = 0; i < downloadWaitingList.size(); i++) { - if (downloadWaitingList.get(i).myRepoName.equals(toCancel.myRepoName) && - downloadWaitingList.get(i).myPath.equals(toCancel.myPath)) { - // Log.d(DEBUG_TAG, "CancelQue " + taskID + " " + toRemove.myRepoName + toRemove.myPath + " in waiting list"); - downloadWaitingList.remove(i); - break; - } - } - } - - if (!downloadingList.isEmpty()) { - for (int i = 0; i< downloadingList.size(); i++) { - if (downloadingList.get(i).myRepoName.equals(toCancel.myRepoName) && - downloadingList.get(i).myPath.equals(toCancel.myPath)) { - // Log.d(DEBUG_TAG, "CancelQue " + taskID + " " + toRemove.myRepoName + toRemove.myPath + " in downloading list"); - downloadingList.remove(i); - break; - } - } - } - } - - } - - public void removeCancelledUploadItemInQue(int taskID) { - - synchronized (uploadWaitingList) { - - UploadTask toCancel = getUploadTaskByID(taskID); - - if (!uploadWaitingList.isEmpty()) { - for (int i = 0; i < uploadWaitingList.size(); i++) { - if (uploadWaitingList.get(i).myPath.equals(toCancel.myPath)) { - // Log.d(DEBUG_TAG, "CancelQue " + taskID + " " + toCancel.myPath + " in waiting list"); - uploadWaitingList.remove(i); - break; - } - } - } - - if (!uploadingList.isEmpty()) { - for (int i = 0; i< uploadingList.size(); i++) { - if (uploadingList.get(i).myPath.equals(toCancel.myPath)) { - // Log.d(DEBUG_TAG, "CancelQue " + taskID + " " + toCancel.myPath + " in uploading list"); - uploadingList.remove(i); - break; - } - } - } - } - - } + protected List transferringList = Lists.newArrayList(); + /** + * contains waiting tasks + */ + protected List waitingList = Lists.newArrayList(); - private UploadTask getUploadTaskByID(int taskID) { - for (UploadTask task : uploadTasks) { + protected TransferTask getTask(int taskID) { + for (TransferTask task : allTaskList) { if (task.getTaskID() == taskID) { return task; } @@ -355,8 +46,8 @@ private UploadTask getUploadTaskByID(int taskID) { return null; } - public UploadTaskInfo getUploadTaskInfo (int taskID) { - UploadTask task = getUploadTaskByID(taskID); + public TransferTaskInfo getTaskInfo(int taskID) { + TransferTask task = getTask(taskID); if (task != null) { return task.getTaskInfo(); } @@ -364,423 +55,100 @@ public UploadTaskInfo getUploadTaskInfo (int taskID) { return null; } - public List getAllUploadTaskInfos() { - ArrayList infos = Lists.newArrayList(); - for (UploadTask task : uploadTasks) { - infos.add(task.getTaskInfo()); + private boolean hasInQue(TransferTask transferTask) { + if (waitingList.contains(transferTask)) { + // Log.d(DEBUG_TAG, "in Que " + taskID + " " + repoName + path + "in waiting list"); + return true; } - return infos; - } - - public List getAllDownloadTaskInfos() { - ArrayList infos = Lists.newArrayList(); - for (DownloadTask task : downloadTasks) { - infos.add(task.getTaskInfo()); + if (transferringList.contains(transferTask)) { + // Log.d(DEBUG_TAG, "in Que " + taskID + " " + repoName + path + " in downloading list"); + return true; } - - return infos; + return false; } - /** - * get all download task info under a specific directory. - * - * @param repoID - * @param dir valid dir should be something like this "/DIRNAME/", instead of "/DIRNAME", - * in order to ensure the param being consistent with its caller - * @return List - */ - public List getDownloadTaskInfosByPath(String repoID, String dir) { - ArrayList infos = Lists.newArrayList(); - for (DownloadTask task : downloadTasks) { - String parentDir = Utils.getParentPath(task.myPath); - String validDir; + protected void addTaskToQue(TransferTask task) { + if (!hasInQue(task)) { + // remove the cancelled or failed task if any + allTaskList.remove(task); - if (!parentDir.equals("/")) - validDir = parentDir + "/"; - else - validDir = parentDir; + // add new created task + allTaskList.add(task); - if (task.myRepoID.equals(repoID) && validDir.equals(dir)) - infos.add(task.getTaskInfo()); + // Log.d(DEBUG_TAG, "add Que " + taskID + " " + repoName + path); + waitingList.add(task); + doNext(); } - - return infos; } - public boolean isDownloading() { - if (downloadTasks.isEmpty()) { - return false; - } + public void doNext() { + if (!waitingList.isEmpty() + && transferringList.size() < TRANSFER_MAX_COUNT) { + Log.d(DEBUG_TAG, "do next!"); - for (DownloadTask task : downloadTasks) { - if (task.getState().equals(TaskState.TRANSFERRING) || task.getState().equals(TaskState.INIT)) { - return true; - } - } - - return false; - } - - public boolean isUploading() { - if (uploadTasks.isEmpty()) - return false; + TransferTask task = waitingList.remove(0); + transferringList.add(task); - for (UploadTask task : uploadTasks) { - if (task.getState().equals(TaskState.INIT) || task.getState().equals(TaskState.TRANSFERRING)) { - return true; - } + ConcurrentAsyncTask.execute(task); } - - return false; } - public void removeUploadTask(int taskID) { - UploadTask task = getUploadTaskByID(taskID); + protected void cancel(int taskID) { + TransferTask task = getTask(taskID); if (task != null) { - uploadTasks.remove(task); - } - } + task.cancel(); - public void removeDownloadTask(int taskID) { - DownloadTask task = getDownloadTaskByID(taskID); - if (task != null) { - downloadTasks.remove(task); } - } - public void removeFinishedUploadTasks() { - Iterator iter = uploadTasks.iterator(); - while (iter.hasNext()) { - UploadTask task = iter.next(); - if (task.getState() == TaskState.FINISHED) { - iter.remove(); - } - } + remove(taskID); } - public void removeAllDownloadTasksByState(TaskState taskState) { - Iterator iter = downloadTasks.iterator(); - while (iter.hasNext()) { - DownloadTask task = iter.next(); - if (task.getState().equals(taskState)) { - iter.remove(); - } - } - } + protected void remove(int taskID) { - public void removeAllUploadTasksByState(TaskState taskState) { - Iterator iter = uploadTasks.iterator(); - while (iter.hasNext()) { - UploadTask task = iter.next(); - if (task.getState().equals(taskState)) { - iter.remove(); - } - } - } + TransferTask toCancel = getTask(taskID); + if (toCancel == null) + return; - public void cancelUploadTask(int taskID) { - UploadTask task = getUploadTaskByID(taskID); - if (task != null) { - task.cancelUpload(); + if (!waitingList.isEmpty()) { + waitingList.remove(toCancel); } - } - public void cancelDownloadTask(int taskID) { - DownloadTask task = getDownloadTaskByID(taskID); - if (task != null) { - task.cancelDownload(); + if (!transferringList.isEmpty()) { + transferringList.remove(toCancel); } } - public void retryUploadTask(int taskID) { - UploadTask task = getUploadTaskByID(taskID); + public void removeInAllTaskList(int taskID) { + TransferTask task = getTask(taskID); if (task != null) { - task.retryUpload(); + allTaskList.remove(task); } } - public void retryDownloadTask(int taskID) { - DownloadTask task = getDownloadTaskByID(taskID); - if (task != null) { - task.retryDownload(); - } - } - - private DownloadTask getDownloadTaskByID(int taskID) { - for (DownloadTask task : downloadTasks) { - if (task.getTaskID() == taskID) { - return task; + public void removeByState(TaskState taskState) { + Iterator iter = allTaskList.iterator(); + while (iter.hasNext()) { + TransferTask task = iter.next(); + if (task.getState().equals(taskState)) { + iter.remove(); } } - return null; } - public DownloadTaskInfo getDownloadTaskInfo (int taskID) { - DownloadTask task = getDownloadTaskByID(taskID); - if (task != null) { - return task.getTaskInfo(); + public void cancelAll() { + List transferTaskInfos = getAllTaskInfoList(); + for (TransferTaskInfo transferTaskInfo : transferTaskInfos) { + cancel(transferTaskInfo.taskID); } - - return null; } - private class UploadTask extends AsyncTask { - private String myRepoID; - private String myRepoName; - private String myDir; // parent dir - private String myPath; // local file path - private boolean isUpdate; // true if update an existing file - private boolean isCopyToLocal; // false to turn off copy operation - - private TaskState myState; - private int myID; - private long myUploaded; - private long mySize; - private DataManager dataManager; - - SeafException err; - - Account account; - - public UploadTask(Account account, String repoID, String repoName, - String dir, String filePath, boolean isUpdate, boolean isCopyToLocal) { - this.account = account; - this.myRepoID = repoID; - this.myRepoName = repoName; - this.myDir = dir; - this.myPath = filePath; - this.isUpdate = isUpdate; - this.isCopyToLocal = isCopyToLocal; - this.dataManager = new DataManager(account); - - File f = new File(filePath); - mySize = f.length(); - - myID = ++notificationID; - myState = TaskState.INIT; - myUploaded = 0; - - // Log.d(DEBUG_TAG, "stored object is " + myPath + myObjectID); - uploadTasks.add(this); - err = null; - } - - public int getTaskID() { - return myID; - } - - public TaskState getState() { - return myState; - } - - public UploadTaskInfo getTaskInfo() { - UploadTaskInfo info = new UploadTaskInfo(account, myID, myState, myRepoID, - myRepoName, myDir, myPath, isUpdate, isCopyToLocal, - myUploaded, mySize, err); - return info; - } - - public void retryUpload() { - if (myState != TaskState.CANCELLED && myState != TaskState.FAILED) { - return; - } - uploadTasks.remove(this); - addTaskToUploadQue(account, myRepoID, myRepoName, myDir, myPath, isUpdate, isCopyToLocal); - } - - public void cancelUpload() { - if (myState != TaskState.INIT && myState != TaskState.TRANSFERRING) { - return; - } - myState = TaskState.CANCELLED; - - removeCancelledUploadItemInQue(myID); - super.cancel(true); - } - - @Override - protected void onPreExecute() { - myState = TaskState.TRANSFERRING; - } - - @Override - protected void onProgressUpdate(Long... values) { - long uploaded = values[0]; - // Log.d(DEBUG_TAG, "Uploaded " + uploaded); - myUploaded = uploaded; - listener.onFileUploadProgress(myID); - } - - @Override - protected Void doInBackground(String... params) { - try { - ProgressMonitor monitor = new ProgressMonitor() { - @Override - public void onProgressNotify(long uploaded) { - publishProgress(uploaded); - } - - @Override - public boolean isCancelled() { - return UploadTask.this.isCancelled(); - } - }; - if (isUpdate) { - dataManager.updateFile(myRepoName, myRepoID, myDir, myPath, monitor, isCopyToLocal); - } else { - // Log.d(DEBUG_TAG, "Upload path: " + myPath); - dataManager.uploadFile(myRepoName, myRepoID, myDir, myPath, monitor, isCopyToLocal); - } - } catch (SeafException e) { - Log.d(DEBUG_TAG, "Upload exception " + e.getCode() + " " + e.getMessage()); - err = e; - } - - return null; - } - - @Override - protected void onPostExecute(Void v) { - myState = err == null ? TaskState.FINISHED : TaskState.FAILED; - if (listener != null) { - if (err == null) { - listener.onFileUploaded(myID); - } - else { - listener.onFileUploadFailed(myID); - } - } - - uploadNextInQue(myID); - } - - @Override - protected void onCancelled() { - if (listener != null) { - listener.onFileUploadCancelled(myID); - } - } - } - - private class DownloadTask extends AsyncTask { - private int taskID; - - Account account; - private String myRepoName; - private String myRepoID; - private String myPath, myLocalPath; - private long mySize, finished; - private TaskState myState; - SeafException err; - - public DownloadTask(Account account, String repoName, String repoID, String path) { - this.account = account; - this.myRepoName = repoName; - this.myRepoID = repoID; - this.myPath = path; - this.myState = TaskState.INIT; - - // The size of the file would be known in the first progress update - this.mySize = -1; - this.taskID = ++notificationID; - - // Log.d(DEBUG_TAG, "stored object is " + myPath + myObjectID); - downloadTasks.add(this); - err = null; - } - - /** - * When downloading a file, we don't know the file size in advance, so - * we make use of the first progress update to return the file size. - */ - @Override - protected void onProgressUpdate(Long... values) { - if (mySize == -1) { - mySize = values[0]; - myState = TaskState.TRANSFERRING; - return; - } - finished = values[0]; - listener.onFileDownloadProgress(taskID); - } - - @Override - protected File doInBackground(String... params) { - try { - DataManager dataManager = new DataManager(account); - return dataManager.getFile(myRepoName, myRepoID, myPath, - new ProgressMonitor() { - - @Override - public void onProgressNotify(long total) { - publishProgress(total); - } - - @Override - public boolean isCancelled() { - return DownloadTask.this.isCancelled(); - } - } - ); - } catch (SeafException e) { - err = e; - return null; - } - } - - @Override - protected void onPostExecute(File file) { - if (listener != null) { - if (file != null) { - myState = TaskState.FINISHED; - myLocalPath = file.getPath(); - listener.onFileDownloaded(taskID); - } else { - myState = TaskState.FAILED; - if (err == null) - err = SeafException.unknownException; - listener.onFileDownloadFailed(taskID); - } - } - - downloadNextInQue(taskID); - } - - @Override - protected void onCancelled() { - myState = TaskState.CANCELLED; - } - - public int getTaskID() { - return taskID; - } - - public DownloadTaskInfo getTaskInfo() { - DownloadTaskInfo info = new DownloadTaskInfo(account, taskID, myState, myRepoID, - myRepoName, myPath, myLocalPath, mySize, finished, err); - return info; - } - - public void cancelDownload() { - if (myState != TaskState.INIT && myState != TaskState.TRANSFERRING) { - return; - } - myState = TaskState.CANCELLED; - removeCancelledDownloadItemInQue(taskID); - super.cancel(true); - } - - public void retryDownload() { - if (myState != TaskState.CANCELLED && myState != TaskState.FAILED) { - return; - } - downloadTasks.remove(this); - addTaskToDownloadQue(account, myRepoName, myRepoID, myPath); + public List getAllTaskInfoList() { + ArrayList infos = Lists.newArrayList(); + for (TransferTask task : allTaskList) { + infos.add(task.getTaskInfo()); } - public TaskState getState() { - return myState; - } + return infos; } } diff --git a/src/com/seafile/seadroid2/transfer/TransferService.java b/src/com/seafile/seadroid2/transfer/TransferService.java index e6cdf4b79..b2ad54038 100644 --- a/src/com/seafile/seadroid2/transfer/TransferService.java +++ b/src/com/seafile/seadroid2/transfer/TransferService.java @@ -1,48 +1,30 @@ package com.seafile.seadroid2.transfer; -import java.io.File; -import java.util.List; - import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import android.support.v4.content.LocalBroadcastManager; import android.util.Log; - -import com.google.common.collect.Lists; import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.transfer.TransferManager.TransferListener; -import com.seafile.seadroid2.util.Utils; -public class TransferService extends Service implements TransferListener { - public static final String BROADCAST_ACTION = "com.seafile.seadroid.TX_BROADCAST"; - public static final String BROADCAST_FILE_DOWNLOAD_SUCCESS = "downloaded"; - public static final String BROADCAST_FILE_DOWNLOAD_FAILED = "downloadFailed"; - public static final String BROADCAST_FILE_DOWNLOAD_PROGRESS = "downloadProgress"; - - public static final String BROADCAST_FILE_UPLOAD_SUCCESS = "uploaded"; - public static final String BROADCAST_FILE_UPLOAD_FAILED = "uploadFailed"; - public static final String BROADCAST_FILE_UPLOAD_PROGRESS = "uploadProgress"; - public static final String BROADCAST_FILE_UPLOAD_CANCELLED = "uploadCancelled"; +import java.util.List; +public class TransferService extends Service { private static final String DEBUG_TAG = "TransferService"; private final IBinder mBinder = new TransferBinder(); - private TransferManager txManager; + private DownloadTaskManager downloadTaskManager; + private UploadTaskManager uploadTaskManager; @Override public void onCreate() { - txManager = new TransferManager(); - txManager.setListener(this); - + downloadTaskManager = new DownloadTaskManager(); + uploadTaskManager = new UploadTaskManager(); } @Override public void onDestroy() { Log.d(DEBUG_TAG, "onDestroy"); - txManager.unsetListener(); - } @Override @@ -61,10 +43,16 @@ public IBinder onBind(Intent intent) { // Log.d(DEBUG_TAG, "onBind"); return mBinder; } - + + // -------------------------- upload task --------------------// + public void addTaskToUploadQue(Account account, String repoID, String repoName, String dir, + String filePath, boolean isUpdate, boolean isCopyToLocal) { + uploadTaskManager.addTaskToQue(account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal); + } + /** * call this method to handle upload request, like file upload or camera upload. - * + * * Note: use isCopyToLocal to mark automatic camera upload if true, or file upload if false. * @param account * @param repoID @@ -75,225 +63,94 @@ public IBinder onBind(Intent intent) { * @param isCopyToLocal * @return */ - public int addUploadTask(Account account, String repoID, String repoName, String dir, + public void addUploadTask(Account account, String repoID, String repoName, String dir, String filePath, boolean isUpdate, boolean isCopyToLocal) { - return addTaskToUploadQue(account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal); - } - - public int addTaskToUploadQue(Account account, String repoID, String repoName, String dir, - String filePath, boolean isUpdate, boolean isCopyToLocal) { - return txManager.addTaskToUploadQue(account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal); - } - - public int addDownloadTask(Account account, String repoName, String repoID, String path) { - return addTaskToDownloadQue(account, repoName, repoID, path); - } - - public int addTaskToDownloadQue(Account account, String repoName, String repoID, String path) { - return txManager.addTaskToDownloadQue(account, repoName, repoID, path); - } - - public boolean isDownloading() { - return txManager.isDownloading(); - } - - public boolean isUploading() { - return txManager.isUploading(); + addTaskToUploadQue(account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal); } public UploadTaskInfo getUploadTaskInfo(int taskID) { - return txManager.getUploadTaskInfo(taskID); + return (UploadTaskInfo) uploadTaskManager.getTaskInfo(taskID); } public List getAllUploadTaskInfos() { - return txManager.getAllUploadTaskInfos(); - } - - public List getAllDownloadTaskInfos() { - return txManager.getAllDownloadTaskInfos(); - } - - public List getDownloadTaskInfosByPath(String repoID, String dir) { - return txManager.getDownloadTaskInfosByPath(repoID, dir); - } - - public void removeUploadTask(int taskID) { - txManager.removeUploadTask(taskID); - } - - public void removeDownloadTask(int taskID) { - txManager.removeDownloadTask(taskID); - } - - public void removeAllDownloadTasksByState(TransferManager.TaskState taskState) { - txManager.removeAllDownloadTasksByState(taskState); - + return (List) uploadTaskManager.getAllTaskInfoList(); } - public void removeAllUploadTasksByState(TransferManager.TaskState taskState) { - txManager.removeAllUploadTasksByState(taskState); - - } + public void removeAllUploadTasksByState(TaskState taskState) { + uploadTaskManager.removeByState(taskState); - public void removeFinishedUploadTasks() { - txManager.removeFinishedUploadTasks(); - } - - public void cancelUploadTask(int taskID) { - txManager.cancelUploadTask(taskID); } public void cancelUploadTaskInQue(int taskID) { - cancelUploadTask(taskID); - txManager.removeCancelledUploadItemInQue(taskID); - txManager.uploadNext(); + uploadTaskManager.cancel(taskID); + uploadTaskManager.doNext(); } public void cancelAllUploadTasks() { - List uploadTaskInfos = txManager.getAllUploadTaskInfos(); - for (TransferTaskInfo uploadTaskInfo : uploadTaskInfos) { - cancelUploadTask(uploadTaskInfo.taskID); - } - + uploadTaskManager.cancelAll(); } public void cancelAllCameraUploadTasks() { - List uploadTaskInfos = getAllUploadTaskInfos(); - for (UploadTaskInfo uploadTaskInfo : uploadTaskInfos) { - // use isCopyToLocal as a flag to mark a camera photo upload task if false - // mark a file upload task if true - if (!uploadTaskInfo.isCopyToLocal) { - cancelUploadTask(uploadTaskInfo.taskID); - } - } + uploadTaskManager.cancelAllCameraUploadTasks(); } public void retryUploadTask(int taskID) { - txManager.retryUploadTask(taskID); + uploadTaskManager.retry(taskID); } - public void retryDownloadTask(int taskID) { - txManager.retryDownloadTask(taskID); - } - - public DownloadTaskInfo getDownloadTaskInfo(int taskID) { - return txManager.getDownloadTaskInfo(taskID); + public void removeUploadTask(int taskID) { + uploadTaskManager.removeInAllTaskList(taskID); } - @Override - public void onFileUploadProgress(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_UPLOAD_PROGRESS).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + // -------------------------- download task --------------------// + public int addDownloadTask(Account account, String repoName, String repoID, String path) { + return downloadTaskManager.addTask(account, repoName, repoID, path); } - @Override - public void onFileUploaded(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_UPLOAD_SUCCESS).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + public void addTaskToDownloadQue(Account account, String repoName, String repoID, String path) { + downloadTaskManager.addTaskToQue(account, repoName, repoID, path); } - @Override - public void onFileUploadCancelled(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_UPLOAD_CANCELLED).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + public List getAllDownloadTaskInfos() { + return (List) downloadTaskManager.getAllTaskInfoList(); } - @Override - public void onFileUploadFailed(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_UPLOAD_FAILED).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + public int getDownloadingFileCountByPath(String repoID, String dir) { + return downloadTaskManager.getDownloadingFileCountByPath(repoID, dir); } - @Override - public void onFileDownloadProgress(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_DOWNLOAD_PROGRESS).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + public List getDownloadTaskInfosByPath(String repoID, String dir) { + return downloadTaskManager.getTaskInfoListByPath(repoID, dir); } - @Override - public void onFileDownloaded(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_DOWNLOAD_SUCCESS).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + public void removeDownloadTask(int taskID) { + downloadTaskManager.removeInAllTaskList(taskID); } - @Override - public void onFileDownloadFailed(int taskID) { - Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", - BROADCAST_FILE_DOWNLOAD_FAILED).putExtra("taskID", taskID); - LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); - } + public void removeAllDownloadTasksByState(TaskState taskState) { + downloadTaskManager.removeByState(taskState); - public void cancelDownloadTask(int taskID) { - txManager.cancelDownloadTask(taskID); } - public void cancelDownloadTaskInQue(int taskID) { - cancelDownloadTask(taskID); - txManager.removeCancelledDownloadItemInQue(taskID); - txManager.downloadNext(); + public void retryDownloadTask(int taskID) { + downloadTaskManager.retry(taskID); } - public void cancellAllDownloadTasks() { - List downloadTaskInfos = txManager.getAllDownloadTaskInfos(); - for (DownloadTaskInfo downloadTaskInfo : downloadTaskInfos) { - cancelDownloadTask(downloadTaskInfo.taskID); - } + public DownloadTaskInfo getDownloadTaskInfo(int taskID) { + return (DownloadTaskInfo) downloadTaskManager.getTaskInfo(taskID); } -} - -interface TransferDBHelper { - void saveUploadTaskInfo(); - - void removeUploadTaskInfo(); - - List getUploadTaskInfoList(); -} - -interface UpdateTaskListener { - void onTaskSuccess(UploadTaskInfo info); - - void onTaskFailed(UploadTaskInfo info); -} - -/** - * Retries to auto update changed files util the update succeeds. - */ -class PersistentTransferScheduler implements UpdateTaskListener { - TransferDBHelper helper; - TransferService service; - - public void addPersistentUpdateTask() { + public void cancelDownloadTask(int taskID) { + cancelDownloadTaskInQue(taskID); } - @Override - public void onTaskFailed(UploadTaskInfo info) { + public void cancelDownloadTaskInQue(int taskID) { + downloadTaskManager.cancel(taskID); + downloadTaskManager.doNext(); } - @Override - public void onTaskSuccess(UploadTaskInfo info) { + public void cancellAllDownloadTasks() { + downloadTaskManager.cancelAll(); } - public void callback() { - if (!Utils.isNetworkOn()) { - return; - } - - for (UploadTaskInfo info : helper.getUploadTaskInfoList()) { - Account account = null; - File file = new File(info.localFilePath); - if (!file.exists()) { - continue; - } - - service.addUploadTask(account, info.repoID, info.repoName, info.parentDir, - info.localFilePath, true, true); - } - } } diff --git a/src/com/seafile/seadroid2/transfer/TransferTask.java b/src/com/seafile/seadroid2/transfer/TransferTask.java new file mode 100644 index 000000000..bb6cdc6b2 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/TransferTask.java @@ -0,0 +1,111 @@ +package com.seafile.seadroid2.transfer; + +import android.os.AsyncTask; +import com.seafile.seadroid2.SeafException; +import com.seafile.seadroid2.account.Account; + +import java.io.File; + +/** + * Base class for transferring data + *

+ * reference for override equals and hashcode, http://www.javaranch.com/journal/2002/10/equalhash.html + *

+ * Created by Logan on 15/2/5. + */ +public abstract class TransferTask extends AsyncTask { + + protected int taskID; + protected Account account; + protected String repoName; + protected String repoID; + protected String path; + protected long totalSize, finished; + protected TaskState state; + protected SeafException err; + + public TransferTask(int taskID, Account account, String repoName, String repoID, String path) { + this.account = account; + this.repoName = repoName; + this.repoID = repoID; + this.path = path; + this.state = TaskState.INIT; + + // The size of the file would be known in the first progress update + this.totalSize = -1; + this.taskID = taskID; + } + + protected void cancel() { + if (state != TaskState.INIT && state != TaskState.TRANSFERRING) { + return; + } + state = TaskState.CANCELLED; + super.cancel(true); + } + + protected boolean canRetry() { + return state == TaskState.CANCELLED || state == TaskState.FAILED; + } + + protected abstract TransferTaskInfo getTaskInfo(); + + public int getTaskID() { + return taskID; + } + + public TaskState getState() { + return state; + } + + public Account getAccount() { + return account; + } + + public String getRepoName() { + return repoName; + } + + public String getRepoID() { + return repoID; + } + + public long getTotalSize() { + return totalSize; + } + + public long getFinished() { + return finished; + } + + public String getPath() { + return path; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if ((obj == null) || (obj.getClass() != this.getClass())) + return false; + TransferTask tt = (TransferTask) obj; + return (account.getSignature() == tt.account.getSignature() || (account.getSignature() != null && account.getSignature().equals(tt.account.getSignature()))) + && (repoID == tt.repoID || (repoID != null && repoID.equals(tt.repoID))) + && (path == tt.path || (path != null && path.equals(tt.path))); + } + + @Override + public String toString() { + return "email " + account.getEmail() + " server " + account.getServer() + " taskID " + taskID + " repoID " + repoID + + " repoName " + repoName + " path " + path; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 31 * hash + (account.getSignature() == null ? 0 : account.getSignature().hashCode()); + hash = 31 * hash + (repoID == null ? 0 : repoID.hashCode()); + hash = 31 * hash + (path == null ? 0 : path.hashCode()); + return hash; + } +} diff --git a/src/com/seafile/seadroid2/transfer/TransferTaskInfo.java b/src/com/seafile/seadroid2/transfer/TransferTaskInfo.java index 215f50ccd..2bcd762b2 100644 --- a/src/com/seafile/seadroid2/transfer/TransferTaskInfo.java +++ b/src/com/seafile/seadroid2/transfer/TransferTaskInfo.java @@ -2,12 +2,13 @@ import com.seafile.seadroid2.SeafException; import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.transfer.TransferManager.TaskState; -/* - * base class for {@link DownloadTaskInfo} and {@link UploadTaskInfo} +/** + * Base class + *

+ * reference for override equals and hashcode, http://www.javaranch.com/journal/2002/10/equalhash.html */ -public class TransferTaskInfo{ +public class TransferTaskInfo { public final Account account; public final int taskID; public final TaskState state; @@ -17,15 +18,15 @@ public class TransferTaskInfo{ public final SeafException err; /** - * Construct a Transfer Task Info instance + * Constructor * - * @param account Current login Account instance - * @param taskID TransferTask id - * @param state TransferTask state, value is one of INIT, TRANSFERRING, FINISHED, CANCELLED, FAILED of {@link TaskState} - * @param repoID Repository id - * @param repoName Repository name + * @param account Current login Account instance + * @param taskID TransferTask id + * @param state TransferTask state, value is one of INIT, TRANSFERRING, FINISHED, CANCELLED, FAILED of {@link TaskState} + * @param repoID Repository id + * @param repoName Repository name * @param localPath Local path - * @param err Exception instance of {@link SeafException} + * @param err Exception instance of {@link SeafException} */ public TransferTaskInfo(Account account, int taskID, TaskState state, String repoID, String repoName, String localPath, @@ -41,15 +42,14 @@ public TransferTaskInfo(Account account, int taskID, TaskState state, String rep @Override public boolean equals(Object obj) { - if (!(obj instanceof TransferTaskInfo)) - return false; if (obj == this) return true; - + if ((obj == null) || (obj.getClass() != this.getClass())) + return false; TransferTaskInfo tti = (TransferTaskInfo) obj; - return tti.account.getSignature().equals(account.getSignature()) - && Integer.compare(tti.taskID, taskID) == 0 - && tti.repoID.equals(repoID); + return (account.getSignature() == tti.account.getSignature() || (account.getSignature() != null && account.getSignature().equals(tti.account.getSignature()))) + && (repoID == tti.repoID || (repoID != null && repoID.equals(tti.repoID))) + && (localFilePath == tti.localFilePath || (localFilePath != null && localFilePath.equals(tti.localFilePath))); } @Override @@ -60,6 +60,10 @@ public String toString() { @Override public int hashCode() { - return String.format("%s%s%d", taskID, repoName, localFilePath).hashCode(); + int hash = 7; + hash = 31 * hash + (account.getSignature() == null ? 0 : account.getSignature().hashCode()); + hash = 31 * hash + (repoID == null ? 0 : repoID.hashCode()); + hash = 31 * hash + (localFilePath == null ? 0 : localFilePath.hashCode()); + return hash; } } diff --git a/src/com/seafile/seadroid2/transfer/UploadStateListener.java b/src/com/seafile/seadroid2/transfer/UploadStateListener.java new file mode 100644 index 000000000..31f5e13e5 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/UploadStateListener.java @@ -0,0 +1,13 @@ +package com.seafile.seadroid2.transfer; + +/** + * Upload state listener + * + * Created by Logan on 15/2/7. + */ +public interface UploadStateListener { + void onFileUploadProgress(int taskID); + void onFileUploaded(int taskID); + void onFileUploadCancelled(int taskID); + void onFileUploadFailed(int taskID); +} diff --git a/src/com/seafile/seadroid2/transfer/UploadTask.java b/src/com/seafile/seadroid2/transfer/UploadTask.java new file mode 100644 index 000000000..736051866 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/UploadTask.java @@ -0,0 +1,130 @@ +package com.seafile.seadroid2.transfer; + +import android.util.Log; +import com.seafile.seadroid2.SeafException; +import com.seafile.seadroid2.account.Account; +import com.seafile.seadroid2.data.DataManager; +import com.seafile.seadroid2.data.ProgressMonitor; + +import java.io.File; + +/** + * Upload task + * + * Created by Logan on 15/2/3. + */ +public class UploadTask extends TransferTask { + public static final String DEBUG_TAG = "UploadTask"; + + private String dir; // parent dir + private boolean isUpdate; // true if update an existing file + private boolean isCopyToLocal; // false to turn off copy operation + private UploadStateListener uploadStateListener; + + private DataManager dataManager; + + public UploadTask(int taskID, Account account, String repoID, String repoName, + String dir, String filePath, boolean isUpdate, boolean isCopyToLocal, + UploadStateListener uploadStateListener) { + super(taskID, account, repoName, repoID, filePath); + this.dir = dir; + this.isUpdate = isUpdate; + this.isCopyToLocal = isCopyToLocal; + this.uploadStateListener = uploadStateListener; + + this.totalSize = new File(filePath).length(); + this.finished = 0; + + this.dataManager = new DataManager(account); + } + + public UploadTaskInfo getTaskInfo() { + UploadTaskInfo info = new UploadTaskInfo(account, taskID, state, repoID, + repoName, dir, path, isUpdate, isCopyToLocal, + finished, totalSize, err); + return info; + } + + public void cancelUpload() { + if (state != TaskState.INIT && state != TaskState.TRANSFERRING) { + return; + } + state = TaskState.CANCELLED; + super.cancel(true); + } + + @Override + protected void onPreExecute() { + state = TaskState.TRANSFERRING; + } + + @Override + protected void onProgressUpdate(Long... values) { + long uploaded = values[0]; + Log.d(DEBUG_TAG, "Uploaded " + uploaded); + this.finished = uploaded; + uploadStateListener.onFileUploadProgress(taskID); + } + + @Override + protected File doInBackground(Void... params) { + try { + ProgressMonitor monitor = new ProgressMonitor() { + @Override + public void onProgressNotify(long uploaded) { + publishProgress(uploaded); + } + + @Override + public boolean isCancelled() { + return UploadTask.this.isCancelled(); + } + }; + if (isUpdate) { + dataManager.updateFile(repoName, repoID, dir, path, monitor, isCopyToLocal); + } else { + Log.d(DEBUG_TAG, "Upload path: " + path); + dataManager.uploadFile(repoName, repoID, dir, path, monitor, isCopyToLocal); + } + } catch (SeafException e) { + Log.d(DEBUG_TAG, "Upload exception " + e.getCode() + " " + e.getMessage()); + err = e; + } + + return null; + } + + @Override + protected void onPostExecute(File file) { + state = err == null ? TaskState.FINISHED : TaskState.FAILED; + if (uploadStateListener != null) { + if (err == null) { + uploadStateListener.onFileUploaded(taskID); + } + else { + uploadStateListener.onFileUploadFailed(taskID); + } + } + } + + @Override + protected void onCancelled() { + if (uploadStateListener != null) { + uploadStateListener.onFileUploadCancelled(taskID); + } + uploadStateListener.onFileUploadCancelled(taskID); + } + + public String getDir() { + return dir; + } + + public boolean isCopyToLocal() { + return isCopyToLocal; + } + + public boolean isUpdate() { + return isUpdate; + } + +} \ No newline at end of file diff --git a/src/com/seafile/seadroid2/transfer/UploadTaskInfo.java b/src/com/seafile/seadroid2/transfer/UploadTaskInfo.java index ed942bb8b..5f5cac93e 100644 --- a/src/com/seafile/seadroid2/transfer/UploadTaskInfo.java +++ b/src/com/seafile/seadroid2/transfer/UploadTaskInfo.java @@ -2,8 +2,9 @@ import com.seafile.seadroid2.SeafException; import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.transfer.TransferManager.TaskState; - +/** + * upload task info + */ public class UploadTaskInfo extends TransferTaskInfo { public final String parentDir; diff --git a/src/com/seafile/seadroid2/transfer/UploadTaskManager.java b/src/com/seafile/seadroid2/transfer/UploadTaskManager.java new file mode 100644 index 000000000..ca5cb3d34 --- /dev/null +++ b/src/com/seafile/seadroid2/transfer/UploadTaskManager.java @@ -0,0 +1,80 @@ +package com.seafile.seadroid2.transfer; + +import android.content.Intent; +import android.support.v4.content.LocalBroadcastManager; +import com.seafile.seadroid2.SeadroidApplication; +import com.seafile.seadroid2.account.Account; + +import java.util.List; + +/** + * Upload task manager + *

+ * Created by Logan on 15/2/4. + */ +public class UploadTaskManager extends TransferManager implements UploadStateListener { + private static final String DEBUG_TAG = "UploadTaskManager"; + + public static final String BROADCAST_FILE_UPLOAD_SUCCESS = "uploaded"; + public static final String BROADCAST_FILE_UPLOAD_FAILED = "uploadFailed"; + public static final String BROADCAST_FILE_UPLOAD_PROGRESS = "uploadProgress"; + public static final String BROADCAST_FILE_UPLOAD_CANCELLED = "uploadCancelled"; + + public void addTaskToQue(Account account, String repoID, String repoName, String dir, String filePath, boolean isUpdate, boolean isCopyToLocal) { + // create a new one to avoid IllegalStateException + UploadTask task = new UploadTask(++notificationID, account, repoID, repoName, dir, filePath, isUpdate, isCopyToLocal, this); + addTaskToQue(task); + } + + public void cancelAllCameraUploadTasks() { + List uploadTaskInfos = (List) getAllTaskInfoList(); + for (UploadTaskInfo uploadTaskInfo : uploadTaskInfos) { + // use isCopyToLocal as a flag to mark a camera photo upload task if false + // mark a file upload task if true + if (!uploadTaskInfo.isCopyToLocal) { + cancel(uploadTaskInfo.taskID); + } + } + } + + public void retry(int taskID) { + UploadTask task = (UploadTask) getTask(taskID); + if (task == null || !task.canRetry()) + return; + addTaskToQue(task.getAccount(), task.getRepoID(), task.getRepoName(), task.getDir(), task.getPath(), task.isUpdate(), task.isCopyToLocal()); + } + + // -------------------------- listener method --------------------// + @Override + public void onFileUploadProgress(int taskID) { + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_UPLOAD_PROGRESS).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } + + @Override + public void onFileUploaded(int taskID) { + remove(taskID); + doNext(); + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_UPLOAD_SUCCESS).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } + + @Override + public void onFileUploadCancelled(int taskID) { + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_UPLOAD_CANCELLED).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } + + @Override + public void onFileUploadFailed(int taskID) { + remove(taskID); + doNext(); + Intent localIntent = new Intent(BROADCAST_ACTION).putExtra("type", + BROADCAST_FILE_UPLOAD_FAILED).putExtra("taskID", taskID); + LocalBroadcastManager.getInstance(SeadroidApplication.getAppContext()).sendBroadcast(localIntent); + } + +} diff --git a/src/com/seafile/seadroid2/ui/activity/BrowserActivity.java b/src/com/seafile/seadroid2/ui/activity/BrowserActivity.java index 22da9272e..1000d5ab9 100644 --- a/src/com/seafile/seadroid2/ui/activity/BrowserActivity.java +++ b/src/com/seafile/seadroid2/ui/activity/BrowserActivity.java @@ -24,7 +24,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.provider.MediaStore; @@ -456,7 +455,7 @@ public void onStart() { mTransferReceiver = new TransferReceiver(); } - IntentFilter filter = new IntentFilter(TransferService.BROADCAST_ACTION); + IntentFilter filter = new IntentFilter(TransferManager.BROADCAST_ACTION); LocalBroadcastManager.getInstance(this).registerReceiver(mTransferReceiver, filter); } @@ -949,10 +948,9 @@ public void downloadDir(String direntName) { return; } - String fileName = direntName; final String repoName = navContext.getRepoName(); final String repoID = navContext.getRepoID(); - final String filePath = Utils.pathJoin(navContext.getDirPath(), fileName); + final String filePath = Utils.pathJoin(navContext.getDirPath(), direntName); ConcurrentAsyncTask.execute(new DownloadDirTask(), repoName, repoID, filePath); // Log.d(DEBUG_TAG, "download >> " + repoName + navContext.getDirPath()); @@ -960,9 +958,10 @@ public void downloadDir(String direntName) { private class DownloadDirTask extends AsyncTask > { - String repoName; - String repoID; - String filePath; + private String repoName; + private String repoID; + private String filePath; + private int fileCount; SeafException err = null; @@ -977,24 +976,17 @@ protected List doInBackground(String... params) { repoID = params[1]; filePath = params[2]; + List dirents; try { - return dataManager.getDirentsFromServer(repoID, filePath); + dirents = dataManager.getDirentsFromServer(repoID, filePath); } catch (SeafException e) { err = e; e.printStackTrace(); return null; } - } - - @Override - protected void onPostExecute(List dirents) { - - if (dirents == null) { - if (err != null) - showToast(R.string.transfer_list_network_error); - return; - } + if (dirents == null) + return null; for (SeafDirent seafDirent : dirents) { if (!seafDirent.isDir()) { @@ -1003,16 +995,39 @@ protected void onPostExecute(List dirents) { Utils.pathJoin(filePath, seafDirent.name), seafDirent.id); - if (localCachedFile == null) { - // Log.d(DEBUG_TAG, Utils.pathJoin(repoName, filePath, seafDirent.name)); - txService.addTaskToDownloadQue(account, - repoName, - repoID, - Utils.pathJoin(filePath, - seafDirent.name)); + if (localCachedFile != null) { + continue; } + + // Log.d(DEBUG_TAG, Utils.pathJoin(repoName, filePath, seafDirent.name)); + txService.addTaskToDownloadQue(account, + repoName, + repoID, + Utils.pathJoin(filePath, + seafDirent.name)); } + } + + fileCount = txService.getDownloadingFileCountByPath(repoID, filePath); + + return dirents; + + } + + @Override + protected void onPostExecute(List dirents) { + if (dirents == null) { + if (err != null) + showToast(R.string.transfer_list_network_error); + return; + } + + if (fileCount == 0) + showToast(R.string.transfer_download_no_task); + else + showToast(getString(R.string.transfer_download_started, fileCount)); + // set download tasks info to adapter in order to update download progress in UI thread getReposFragment().getAdapter().setDownloadTaskList(txService.getDownloadTaskInfosByPath(repoID, filePath)); getReposFragment().getAdapter().notifyDataSetChanged(); @@ -1492,16 +1507,16 @@ private TransferReceiver() {} public void onReceive(Context context, Intent intent) { String type = intent.getStringExtra("type"); - if (type.equals(TransferService.BROADCAST_FILE_DOWNLOAD_PROGRESS)) { + if (type.equals(DownloadTaskManager.BROADCAST_FILE_DOWNLOAD_PROGRESS)) { int taskID = intent.getIntExtra("taskID", 0); onFileDownloadProgress(taskID); - } else if (type.equals(TransferService.BROADCAST_FILE_DOWNLOAD_FAILED)) { + } else if (type.equals(DownloadTaskManager.BROADCAST_FILE_DOWNLOAD_FAILED)) { int taskID = intent.getIntExtra("taskID", 0); onFileDownloadFailed(taskID); - } else if (type.equals(TransferService.BROADCAST_FILE_UPLOAD_SUCCESS)) { + } else if (type.equals(UploadTaskManager.BROADCAST_FILE_UPLOAD_SUCCESS)) { int taskID = intent.getIntExtra("taskID", 0); onFileUploaded(taskID); - } else if (type.equals(TransferService.BROADCAST_FILE_UPLOAD_FAILED)) { + } else if (type.equals(UploadTaskManager.BROADCAST_FILE_UPLOAD_FAILED)) { int taskID = intent.getIntExtra("taskID", 0); onFileUploadFailed(taskID); } diff --git a/src/com/seafile/seadroid2/ui/activity/FileActivity.java b/src/com/seafile/seadroid2/ui/activity/FileActivity.java index 9e2811261..d0be76ca6 100644 --- a/src/com/seafile/seadroid2/ui/activity/FileActivity.java +++ b/src/com/seafile/seadroid2/ui/activity/FileActivity.java @@ -31,6 +31,8 @@ import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.data.DataManager; import com.seafile.seadroid2.transfer.DownloadTaskInfo; +import com.seafile.seadroid2.transfer.DownloadTaskManager; +import com.seafile.seadroid2.transfer.TransferManager; import com.seafile.seadroid2.transfer.TransferService; import com.seafile.seadroid2.transfer.TransferService.TransferBinder; import com.seafile.seadroid2.ui.dialog.OpenAsDialog; @@ -193,7 +195,7 @@ public void onDismiss(DialogInterface dialog) { private void onTransferSericeConnected() { // Register broadcast receiver - IntentFilter filter = new IntentFilter(TransferService.BROADCAST_ACTION); + IntentFilter filter = new IntentFilter(TransferManager.BROADCAST_ACTION); mTransferReceiver = new TransferReceiver(); LocalBroadcastManager.getInstance(this).registerReceiver(mTransferReceiver, filter); @@ -313,11 +315,11 @@ public void onReceive(Context context, Intent intent) { if (info == null) { Log.w(DEBUG_TAG, "download info is null"); } - if (type.equals(TransferService.BROADCAST_FILE_DOWNLOAD_PROGRESS)) { + if (type.equals(DownloadTaskManager.BROADCAST_FILE_DOWNLOAD_PROGRESS)) { onFileDownloadProgress(info); - } else if (type.equals(TransferService.BROADCAST_FILE_DOWNLOAD_SUCCESS)) { + } else if (type.equals(DownloadTaskManager.BROADCAST_FILE_DOWNLOAD_SUCCESS)) { onFileDownloaded(info); - } else if (type.equals(TransferService.BROADCAST_FILE_DOWNLOAD_FAILED)) { + } else if (type.equals(DownloadTaskManager.BROADCAST_FILE_DOWNLOAD_FAILED)) { onFileDownloadFailed(info); } } diff --git a/src/com/seafile/seadroid2/ui/activity/TransferActivity.java b/src/com/seafile/seadroid2/ui/activity/TransferActivity.java index 5ba05a5ba..f8d926c2c 100644 --- a/src/com/seafile/seadroid2/ui/activity/TransferActivity.java +++ b/src/com/seafile/seadroid2/ui/activity/TransferActivity.java @@ -99,7 +99,7 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; case R.id.cancel_transfer_tasks: if (currentPosition == 0) { - getDownloadTaskFragment().cancelDownloadTasks(); + getDownloadTaskFragment().cancelAllDownloadTasks(); } else getUploadTaskFragment().cancelUploadTasks(); diff --git a/src/com/seafile/seadroid2/ui/adapter/SeafItemAdapter.java b/src/com/seafile/seadroid2/ui/adapter/SeafItemAdapter.java index f3655aacd..bd6c81f0d 100644 --- a/src/com/seafile/seadroid2/ui/adapter/SeafItemAdapter.java +++ b/src/com/seafile/seadroid2/ui/adapter/SeafItemAdapter.java @@ -67,19 +67,7 @@ public boolean isEmpty() { } /** - * DownloadTask list should not be empty - * - * @return true if files added to download list, false otherwise - */ - public boolean isDownloadTaskListEmpty() { - if (mDownloadTaskInfos == null || mDownloadTaskInfos.isEmpty()) { - return true; - } - return false; - } - - /** - * To refresh download status icons of {@link com.seafile.seadroid2.ui.fragment.ReposFragment #mPullRefreshListView} instantly, + * To refresh downloading status of {@link com.seafile.seadroid2.ui.fragment.ReposFragment #mPullRefreshListView}, * use this method to update data set. *

* This method should be called after the download folder button was clicked. @@ -90,24 +78,6 @@ public void setDownloadTaskList(List downloadTaskInfos) { this.mDownloadTaskInfos = downloadTaskInfos; } - /** - * To refresh download status icon of one specific item of {@link com.seafile.seadroid2.ui.fragment.ReposFragment #mPullRefreshListView} instantly, - * use this method to update data set. - * - * @param downloadTaskInfo - */ - public void setDownloadTask(DownloadTaskInfo downloadTaskInfo) { - if (mDownloadTaskInfos == null) { - mDownloadTaskInfos = Lists.newArrayList(); - } - // remove old data - if (mDownloadTaskInfos.contains(downloadTaskInfo)) { - mDownloadTaskInfos.remove(downloadTaskInfo); - } - - mDownloadTaskInfos.add(downloadTaskInfo); - } - public void addEntry(SeafItem entry) { items.add(entry); // Collections.sort(items); diff --git a/src/com/seafile/seadroid2/ui/adapter/TransferTaskAdapter.java b/src/com/seafile/seadroid2/ui/adapter/TransferTaskAdapter.java index a330c6129..d7fd5da60 100644 --- a/src/com/seafile/seadroid2/ui/adapter/TransferTaskAdapter.java +++ b/src/com/seafile/seadroid2/ui/adapter/TransferTaskAdapter.java @@ -1,10 +1,5 @@ package com.seafile.seadroid2.ui.adapter; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; - import android.content.Context; import android.graphics.Color; import android.view.LayoutInflater; @@ -14,8 +9,6 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; - -import com.google.common.collect.Maps; import com.seafile.seadroid2.R; import com.seafile.seadroid2.transfer.DownloadTaskInfo; import com.seafile.seadroid2.transfer.TransferTaskInfo; @@ -23,6 +16,10 @@ import com.seafile.seadroid2.ui.activity.TransferActivity; import com.seafile.seadroid2.util.Utils; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + /* * Adapter class for both uploading and downloading tasks */ @@ -30,8 +27,7 @@ public class TransferTaskAdapter extends BaseAdapter { private static final String DEBUG_TAG = "TransferTaskAdapter"; - private List mUploadTaskInfos; - private List mDownloadTaskInfos; + private List mTransferTaskInfos; private Context mContext; /** 0 mark as Download Task, 1 mark as Upload Task, the same convention with {@link TransferActivity #currentPosition} */ private int mTransferTaskType = -1; @@ -46,14 +42,11 @@ public class TransferTaskAdapter extends BaseAdapter { * set {@link TransferTaskAdapter #mTransferTaskType} 0 to mark as Download Task, 1 mark to mark as Upload Task
* * @param context - * @param uploadTaskInfos - * @param downloadTaskInfos + * @param transferTaskInfos */ public TransferTaskAdapter(Context context, - List uploadTaskInfos, - List downloadTaskInfos) { - this.mUploadTaskInfos = (List) uploadTaskInfos; - this.mDownloadTaskInfos = (List) downloadTaskInfos; + List transferTaskInfos) { + this.mTransferTaskInfos = transferTaskInfos; this.mContext = context; } @@ -89,46 +82,24 @@ public int compare(TransferTaskInfo infoA, TransferTaskInfo infoB) { } } - public void setUploadTaskInfos(List infos) { - mUploadTaskInfos = infos; - Collections.sort(mUploadTaskInfos, new TaskInfoComparator()); + public void setTransferTaskInfos(List infos) { + mTransferTaskInfos = infos; + Collections.sort(mTransferTaskInfos, new TaskInfoComparator()); } - public void setDownloadTaskInfos(List infos) { - mDownloadTaskInfos = infos; - Collections.sort(mDownloadTaskInfos, new TaskInfoComparator()); - } - @Override public int getCount() { - if (mTransferTaskType == 0) { - return mDownloadTaskInfos.size(); - } else if (mTransferTaskType == 1) { - return mUploadTaskInfos.size(); - } - return -1; + return mTransferTaskInfos.size(); } @Override public boolean isEmpty() { - if (mTransferTaskType == 0) { - return mDownloadTaskInfos.isEmpty(); - } else if (mTransferTaskType == 1) { - return mUploadTaskInfos.isEmpty(); - } - - return true; + return mTransferTaskInfos.isEmpty(); } @Override public TransferTaskInfo getItem(int position) { - if (mTransferTaskType == 0) { - return mDownloadTaskInfos.get(position); - } else if (mTransferTaskType == 1) { - return mUploadTaskInfos.get(position); - } - - return null; + return mTransferTaskInfos.get(position); } @Override @@ -215,9 +186,9 @@ public View getView(int position, View convertView, ViewGroup parent) { viewHolder = (Viewholder) convertView.getTag(); } - int iconID = 0; + int iconID; if (mTransferTaskType == 0) { - DownloadTaskInfo taskInfo = mDownloadTaskInfos.get(position); + DownloadTaskInfo taskInfo = (DownloadTaskInfo) mTransferTaskInfos.get(position); iconID = Utils.getFileIcon(taskInfo.pathInRepo); // the three fileds is not dynamic viewHolder.icon.setImageResource(iconID); @@ -225,7 +196,7 @@ public View getView(int position, View convertView, ViewGroup parent) { viewHolder.fileName.setText(Utils.fileNameFromPath(taskInfo.pathInRepo)); updateTaskView(taskInfo, viewHolder); } else if (mTransferTaskType == 1) { - UploadTaskInfo taskInfo = mUploadTaskInfos.get(position); + UploadTaskInfo taskInfo = (UploadTaskInfo) mTransferTaskInfos.get(position); iconID = Utils.getFileIcon(taskInfo.localFilePath); String fullpath = taskInfo.repoName + taskInfo.parentDir; // the three fileds is not dynamic diff --git a/src/com/seafile/seadroid2/ui/fragment/DownloadTaskFragment.java b/src/com/seafile/seadroid2/ui/fragment/DownloadTaskFragment.java index 7502af402..ac09ec3f1 100644 --- a/src/com/seafile/seadroid2/ui/fragment/DownloadTaskFragment.java +++ b/src/com/seafile/seadroid2/ui/fragment/DownloadTaskFragment.java @@ -2,11 +2,12 @@ import android.os.Bundle; import android.util.Log; -import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import com.seafile.seadroid2.R; -import com.seafile.seadroid2.transfer.*; +import com.seafile.seadroid2.transfer.DownloadTaskInfo; +import com.seafile.seadroid2.transfer.TaskState; +import com.seafile.seadroid2.transfer.TransferTaskInfo; import com.seafile.seadroid2.ui.adapter.TransferTaskAdapter; import java.util.List; @@ -19,8 +20,6 @@ public class DownloadTaskFragment extends TransferTaskFragment { private static final String DEBUG_TAG = "DownloadTaskFragment"; - private boolean isDownloadListVisible; - @Override public void onActivityCreated(Bundle savedInstanceState) { Log.d(DEBUG_TAG, "onActivityCreated"); @@ -30,77 +29,23 @@ public void onActivityCreated(Bundle savedInstanceState) { } @Override - void setUpTransferList(TransferService txService) { + protected List getTransferTaskInfos() { + return txService.getAllDownloadTaskInfos(); + } + + @Override + protected void setUpTransferList() { Log.d(DEBUG_TAG, "bind TransferService"); List infos = txService.getAllDownloadTaskInfos(); - adapter = new TransferTaskAdapter(mActivity, null, infos); + adapter = new TransferTaskAdapter(mActivity, infos); adapter.setCurrentTab(TransferTaskAdapter.DOWNLOAD_LIST_TAB); mTransferTaskListView.setAdapter(adapter); } - @Override - public void onResume() { - Log.d(DEBUG_TAG, "onResume"); - isDownloadListVisible = true; - super.onResume(); - } - - @Override - public void onStop() { - Log.d(DEBUG_TAG, "onStop"); - super.onStop(); - isDownloadListVisible = false; - } - - boolean isNeedUpdateProgress() { - // first download list should at foreground - if (!isDownloadListVisible) { - return false; - } - - // second there are some downloading tasks - if (txService == null) - return false; - - if (!txService.isDownloading()) - return false; - - return true; - } - - // refresh download list by mTimer - void startTimer() { - Log.d(DEBUG_TAG, "timer started"); - mTimer.postDelayed(new Runnable() { - - @Override - public void run() { - adapter.setDownloadTaskInfos(txService.getAllDownloadTaskInfos()); - adapter.notifyDataSetChanged(); - Log.d(DEBUG_TAG, "timer post refresh signal " + System.currentTimeMillis()); - mTimer.postDelayed(this, 1 * 1000); - } - }, 1 * 1000); - } - - @Override - void refreshView() { - List infos = txService.getAllDownloadTaskInfos(); - if (infos == null || infos.isEmpty()) { - mTransferTaskListView.setVisibility(View.GONE); - emptyView.setVisibility(View.VISIBLE); - } else { - if (isNeedUpdateProgress()) - startTimer(); - - mTransferTaskListView.setVisibility(View.VISIBLE); - emptyView.setVisibility(View.GONE); - adapter.setDownloadTaskInfos(infos); - adapter.notifyDataSetChanged(); - } - + protected boolean isNeedUpdateProgress() { + return !txService.getAllDownloadTaskInfos().isEmpty(); } @Override @@ -114,50 +59,39 @@ public boolean onContextItemSelected(android.view.MenuItem item) { ListView listView = mTransferTaskListView; DownloadTaskInfo taskInfo = (DownloadTaskInfo) listView.getItemAtPosition(info.position); - TransferManager.TaskState state = taskInfo.state; + TaskState state = taskInfo.state; int taskID = taskInfo.taskID; - boolean needRefresh = false; - switch (item.getItemId()) { case R.id.cancel: - if (state == TransferManager.TaskState.INIT || state == TransferManager.TaskState.TRANSFERRING) { - // txService.cancelDownloadTask(taskID); + if (state == TaskState.INIT || state == TaskState.TRANSFERRING) { txService.cancelDownloadTaskInQue(taskID); - needRefresh = true; } break; case R.id.retry: - if (state == TransferManager.TaskState.FAILED || state == TransferManager.TaskState.CANCELLED) { + if (state == TaskState.FAILED || state == TaskState.CANCELLED) { txService.retryDownloadTask(taskID); - needRefresh = true; } break; case R.id.remove: - if (state == TransferManager.TaskState.FINISHED || state == TransferManager.TaskState.FAILED || state == TransferManager.TaskState.CANCELLED) { + if (state == TaskState.FINISHED || state == TaskState.FAILED || state == TaskState.CANCELLED) { txService.removeDownloadTask(taskID); - needRefresh = true; } break; case R.id.remove_all_cancelled: - if (state == TransferManager.TaskState.CANCELLED) { - txService.removeAllDownloadTasksByState(TransferManager.TaskState.CANCELLED); - needRefresh = true; + if (state == TaskState.CANCELLED) { + txService.removeAllDownloadTasksByState(TaskState.CANCELLED); } break; case R.id.remove_all_finished: - if (state == TransferManager.TaskState.FINISHED) { - txService.removeAllDownloadTasksByState(TransferManager.TaskState.FINISHED); - needRefresh = true; + if (state == TaskState.FINISHED) { + txService.removeAllDownloadTasksByState(TaskState.FINISHED); } break; default: return super.onContextItemSelected(item); } - if (needRefresh) { - refreshView(); - } return true; } else @@ -167,15 +101,10 @@ public boolean onContextItemSelected(android.view.MenuItem item) { /** * cancel all download tasks */ - public void cancelDownloadTasks() { + public void cancelAllDownloadTasks() { if (txService != null) { txService.cancellAllDownloadTasks(); } - - refreshView(); - - // stop timer - stopTimer(); } } diff --git a/src/com/seafile/seadroid2/ui/fragment/ReposFragment.java b/src/com/seafile/seadroid2/ui/fragment/ReposFragment.java index 5c458a894..f7868adbd 100644 --- a/src/com/seafile/seadroid2/ui/fragment/ReposFragment.java +++ b/src/com/seafile/seadroid2/ui/fragment/ReposFragment.java @@ -61,6 +61,7 @@ public class ReposFragment extends SherlockListFragment { private View mListContainer; private TextView mErrorText; + private boolean isTimerStarted; private final Handler mTimer = new Handler(); private DataManager getDataManager() { @@ -260,6 +261,10 @@ public void navToDirectory(boolean forceRefresh) { // refresh download list by mTimer public void startTimer() { + if (isTimerStarted) + return; + + isTimerStarted = true; Log.d(DEBUG_TAG, "timer started"); mTimer.postDelayed(new Runnable() { @@ -276,6 +281,7 @@ public void run() { public void stopTimer() { Log.d(DEBUG_TAG, "timer stopped"); mTimer.removeCallbacksAndMessages(null); + isTimerStarted = false; } /** diff --git a/src/com/seafile/seadroid2/ui/fragment/SettingsPreferenceFragment.java b/src/com/seafile/seadroid2/ui/fragment/SettingsPreferenceFragment.java index b27db4996..111d3d78d 100644 --- a/src/com/seafile/seadroid2/ui/fragment/SettingsPreferenceFragment.java +++ b/src/com/seafile/seadroid2/ui/fragment/SettingsPreferenceFragment.java @@ -31,6 +31,7 @@ import com.seafile.seadroid2.cameraupload.CameraUploadService; import com.seafile.seadroid2.data.DataManager; import com.seafile.seadroid2.gesturelock.LockPatternUtils; +import com.seafile.seadroid2.transfer.TransferManager; import com.seafile.seadroid2.transfer.TransferService; import com.seafile.seadroid2.ui.SeafileStyleDialogBuilder; import com.seafile.seadroid2.ui.activity.AccountsActivity; @@ -90,7 +91,7 @@ public void onAttach(Activity activity) { LocalBroadcastManager .getInstance(mActivity) .registerReceiver(transferReceiver, - new IntentFilter(TransferService.BROADCAST_ACTION)); + new IntentFilter(TransferManager.BROADCAST_ACTION)); } @Override @@ -197,7 +198,7 @@ public void onViewCreated(View view, Bundle savedInstanceState) { LocalBroadcastManager .getInstance(getActivity().getApplicationContext()) .registerReceiver(transferReceiver, - new IntentFilter(TransferService.BROADCAST_ACTION)); + new IntentFilter(TransferManager.BROADCAST_ACTION)); } diff --git a/src/com/seafile/seadroid2/ui/fragment/TransferTaskFragment.java b/src/com/seafile/seadroid2/ui/fragment/TransferTaskFragment.java index 2337642c3..54e88e69b 100644 --- a/src/com/seafile/seadroid2/ui/fragment/TransferTaskFragment.java +++ b/src/com/seafile/seadroid2/ui/fragment/TransferTaskFragment.java @@ -8,6 +8,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.View; @@ -22,12 +23,15 @@ import com.seafile.seadroid2.ui.activity.TransferActivity; import com.seafile.seadroid2.ui.adapter.TransferTaskAdapter; +import java.util.List; + /** * Base class for transfer task fragments * * Created by Logan on 14/12/22. */ public abstract class TransferTaskFragment extends SherlockListFragment { + private String DEBUG_TAG = "TransferTaskFragment"; protected TransferTaskAdapter adapter; protected TransferActivity mActivity = null; @@ -70,16 +74,20 @@ public void onActivityCreated(Bundle savedInstanceState) { mActivity.bindService(bIntent, mConnection, Context.BIND_AUTO_CREATE); } - ServiceConnection mConnection = new ServiceConnection() { + private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { - TransferService.TransferBinder binder = (TransferService.TransferBinder) service; - txService = binder.getService(); - setUpTransferList(txService); - refreshView(); - // Toast.makeText(mActivity, "Stop loading animations", Toast.LENGTH_LONG).show(); showLoading(false); + + TransferService.TransferBinder binder = (TransferService.TransferBinder) service; + txService = binder.getService(); + if (isNeedUpdateProgress()) { + mTransferTaskListView.setVisibility(View.VISIBLE); + emptyView.setVisibility(View.GONE); + setUpTransferList(); + startTimer(); + } } @Override @@ -88,17 +96,18 @@ public void onServiceDisconnected(ComponentName arg0) { } }; - abstract void setUpTransferList(TransferService txService); + protected abstract List getTransferTaskInfos(); + + protected abstract void setUpTransferList(); @Override public void onResume() { super.onResume(); - // refreshView(); - if (isNeedUpdateProgress()) - startTimer(); + mTransferTaskListView.setVisibility(View.GONE); + emptyView.setVisibility(View.VISIBLE); } - abstract boolean isNeedUpdateProgress(); + protected abstract boolean isNeedUpdateProgress(); @Override public void onStop() { @@ -111,14 +120,24 @@ public void onStop() { } // refresh list by mTimer - abstract void startTimer(); + private void startTimer() { + Log.d(DEBUG_TAG, "timer started"); + mTimer.postDelayed(new Runnable() { + + @Override + public void run() { + adapter.setTransferTaskInfos(getTransferTaskInfos()); + adapter.notifyDataSetChanged(); + Log.d(DEBUG_TAG, "timer post refresh signal " + System.currentTimeMillis()); + mTimer.postDelayed(this, 1 * 1000); + } + }, 1 * 1000); + } public void stopTimer() { mTimer.removeCallbacksAndMessages(null); } - abstract void refreshView(); - private void showLoading(boolean show) { if (mActivity == null) return; diff --git a/src/com/seafile/seadroid2/ui/fragment/UploadTaskFragment.java b/src/com/seafile/seadroid2/ui/fragment/UploadTaskFragment.java index d38246f9e..fa09e4f05 100644 --- a/src/com/seafile/seadroid2/ui/fragment/UploadTaskFragment.java +++ b/src/com/seafile/seadroid2/ui/fragment/UploadTaskFragment.java @@ -1,12 +1,12 @@ package com.seafile.seadroid2.ui.fragment; import android.os.Bundle; -import android.util.Log; -import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import com.seafile.seadroid2.R; -import com.seafile.seadroid2.transfer.*; +import com.seafile.seadroid2.transfer.TaskState; +import com.seafile.seadroid2.transfer.TransferTaskInfo; +import com.seafile.seadroid2.transfer.UploadTaskInfo; import com.seafile.seadroid2.ui.adapter.TransferTaskAdapter; import java.util.List; @@ -19,8 +19,6 @@ public class UploadTaskFragment extends TransferTaskFragment { private static final String DEBUG_TAG = "UploadTaskFragment"; - private boolean isUploadListVisible; - @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -30,72 +28,21 @@ public void onActivityCreated(Bundle savedInstanceState) { } @Override - void setUpTransferList(TransferService txService) { + protected List getTransferTaskInfos() { + return txService.getAllUploadTaskInfos(); + } + + @Override + protected void setUpTransferList() { List infos = txService.getAllUploadTaskInfos(); - adapter = new TransferTaskAdapter(mActivity, infos, null); + adapter = new TransferTaskAdapter(mActivity, infos); adapter.setCurrentTab(TransferTaskAdapter.UPLOAD_LIST_TAB); mTransferTaskListView.setAdapter(adapter); } @Override - public void onResume() { - isUploadListVisible = true; - super.onResume(); - } - - boolean isNeedUpdateProgress() { - // first upload list should at foreground - if (!isUploadListVisible) { - return false; - } - - // second there are some upload tasks - if(txService == null) - return false; - - if (!txService.isUploading()) - return false; - - return true; - } - - @Override - public void onStop() { - super.onStop(); - isUploadListVisible = false; - } - - // refresh upload list by mTimer - void startTimer() { - Log.d(DEBUG_TAG, "timer started"); - mTimer.postDelayed(new Runnable() { - - @Override - public void run() { - adapter.setUploadTaskInfos(txService.getAllUploadTaskInfos()); - adapter.notifyDataSetChanged(); - Log.d(DEBUG_TAG, "timer post refresh signal " + System.currentTimeMillis()); - mTimer.postDelayed(this, 1 * 1000); - } - }, 1 * 1000); - } - - void refreshView() { - - List infos = txService.getAllUploadTaskInfos(); - if (infos == null || infos.isEmpty()) { - mTransferTaskListView.setVisibility(View.GONE); - emptyView.setVisibility(View.VISIBLE); - } else { - if (isNeedUpdateProgress()) - startTimer(); - - mTransferTaskListView.setVisibility(View.VISIBLE); - emptyView.setVisibility(View.GONE); - adapter.setUploadTaskInfos(infos); - adapter.notifyDataSetChanged(); - } - + protected boolean isNeedUpdateProgress() { + return !txService.getAllUploadTaskInfos().isEmpty(); } @Override @@ -109,50 +56,39 @@ public boolean onContextItemSelected(android.view.MenuItem item) { ListView listView = mTransferTaskListView; UploadTaskInfo taskInfo = (UploadTaskInfo) listView.getItemAtPosition(info.position); - TransferManager.TaskState state = taskInfo.state; + TaskState state = taskInfo.state; int taskID = taskInfo.taskID; - boolean needRefresh = false; - switch (item.getItemId()) { case R.id.cancel: - if (state == TransferManager.TaskState.INIT || state == TransferManager.TaskState.TRANSFERRING) { - // txService.cancelUploadTask(taskID); + if (state == TaskState.INIT || state == TaskState.TRANSFERRING) { txService.cancelUploadTaskInQue(taskID); - needRefresh = true; } break; case R.id.retry: - if (state == TransferManager.TaskState.FAILED || state == TransferManager.TaskState.CANCELLED) { + if (state == TaskState.FAILED || state == TaskState.CANCELLED) { txService.retryUploadTask(taskID); - needRefresh = true; } break; case R.id.remove: - if (state == TransferManager.TaskState.FINISHED || state == TransferManager.TaskState.FAILED || state == TransferManager.TaskState.CANCELLED) { + if (state == TaskState.FINISHED || state == TaskState.FAILED || state == TaskState.CANCELLED) { txService.removeUploadTask(taskID); - needRefresh = true; } break; case R.id.remove_all_cancelled: - if (state == TransferManager.TaskState.CANCELLED) { - txService.removeAllUploadTasksByState(TransferManager.TaskState.CANCELLED); - needRefresh = true; + if (state == TaskState.CANCELLED) { + txService.removeAllUploadTasksByState(TaskState.CANCELLED); } break; case R.id.remove_all_finished: - if (state == TransferManager.TaskState.FINISHED) { - txService.removeFinishedUploadTasks(); - needRefresh = true; + if (state == TaskState.FINISHED) { + txService.removeAllUploadTasksByState(TaskState.FINISHED); } break; default: return super.onContextItemSelected(item); } - if (needRefresh) { - refreshView(); - } return true; } else @@ -169,10 +105,5 @@ public void cancelUploadTasks() { if (txService != null) { txService.cancelAllUploadTasks(); } - - refreshView(); - - // stop timer - stopTimer(); } } \ No newline at end of file