From f5100dee23fe4ceabd380883f99d26bce7316668 Mon Sep 17 00:00:00 2001 From: zhwanng <48609908+zhwanng@users.noreply.github.com> Date: Sat, 29 Jun 2024 16:23:56 +0800 Subject: [PATCH] fix bugs - v3.0.1-beta --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 5 + .../seafile/seadroid2/config/Constants.java | 4 +- .../data/db/dao/FileTransferDAO.java | 26 +- .../framework/datastore/DataManager.java | 20 + .../datastore/sp/FolderBackupManager.java | 26 +- .../datastore/sp/SettingsManager.java | 9 + .../file_monitor/FileSyncService.java | 29 +- .../seadroid2/framework/http/BaseIO.java | 57 +-- .../AlbumBackupNotificationHelper.java | 11 +- .../AlbumBackupScanNotificationHelper.java | 44 ++ .../DownloadNotificationHelper.java | 7 +- .../FileBackupNotificationHelper.java | 13 +- .../FolderBackupNotificationHelper.java | 11 +- .../FolderBackupScanNotificationHelper.java | 44 ++ .../GeneralNotificationHelper.java | 8 + .../UploadNotificationHelper.java | 45 -- .../notification/base/BaseNotification.java | 53 ++- .../base/BaseTransferNotificationHelper.java | 62 ++- .../notification/base/NotificationUtils.java | 11 +- .../seadroid2/framework/util/Objs.java | 32 +- .../framework/util/TransferUtils.java | 5 +- .../worker/BackgroundJobManagerImpl.java | 26 +- .../worker/BaseDownloadFileWorker.java | 28 -- .../framework/worker/BaseWorker.java | 2 +- .../DownloadedFileCheckerWorkerBak.java | 163 -------- .../worker/FolderBackupScannerWorker.java | 318 --------------- .../framework/worker/TransferEvent.java | 45 +- .../framework/worker/TransferWorker.java | 204 +++++---- .../framework/worker/UploadWorker.java | 129 ------ .../worker/body/ProgressRequestBody.java | 2 +- .../worker/download/BaseDownloadWorker.java | 108 +++++ .../DownloadFileScanWorker.java | 28 +- .../worker/{ => download}/DownloadWorker.java | 81 ++-- .../DownloadedFileCheckerWorker.java | 26 +- .../BaseUploadWorker.java} | 386 +++++++++++++----- .../upload/FolderBackupScannerWorker.java | 339 +++++++++++++++ .../MediaBackupScannerWorker.java | 63 ++- .../UploadFileManuallyWorker.java | 96 +++-- .../UploadFolderFileAutomaticallyWorker.java | 114 +++--- .../UploadMediaFileAutomaticallyWorker.java | 102 +++-- .../ssl/SSLSeafileSocketFactory.java | 1 + .../seadroid2/ssl/SSLTrustManager.java | 2 +- .../ui/activities/AllActivitiesFragment.java | 30 +- .../ui/base/fragment/BaseFragment.java | 21 + .../ui/base/viewmodel/BaseViewModel.java | 7 +- .../ui/camera_upload/AlbumBackupAdapter.java | 6 + .../FolderBackupSelectedPathActivity.java | 75 +++- .../seadroid2/ui/main/MainActivity.java | 34 ++ .../seadroid2/ui/repo/RepoQuickFragment.java | 45 +- .../seadroid2/ui/repo/RepoService.java | 5 + .../seadroid2/ui/repo/RepoViewModel.java | 4 +- .../ui/settings/SettingsFragment.java | 89 ++-- .../settings/SettingsFragmentViewModel.java | 26 +- .../ui/star/StarredQuickFragment.java | 12 +- .../transfer_list/DownloadListFragment.java | 48 ++- .../ui/transfer_list/TransferListAdapter.java | 30 +- .../transfer_list/TransferListFragment.java | 88 +++- .../transfer_list/TransferListViewModel.java | 77 +++- .../ui/transfer_list/UploadListFragment.java | 53 ++- app/src/main/res/values/strings.xml | 1 + build_count.txt | 2 +- 62 files changed, 2051 insertions(+), 1389 deletions(-) create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupScanNotificationHelper.java create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupScanNotificationHelper.java delete mode 100644 app/src/main/java/com/seafile/seadroid2/framework/notification/UploadNotificationHelper.java delete mode 100644 app/src/main/java/com/seafile/seadroid2/framework/worker/BaseDownloadFileWorker.java delete mode 100644 app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorkerBak.java delete mode 100644 app/src/main/java/com/seafile/seadroid2/framework/worker/FolderBackupScannerWorker.java delete mode 100644 app/src/main/java/com/seafile/seadroid2/framework/worker/UploadWorker.java create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => download}/DownloadFileScanWorker.java (94%) rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => download}/DownloadWorker.java (87%) rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => download}/DownloadedFileCheckerWorker.java (89%) rename app/src/main/java/com/seafile/seadroid2/framework/worker/{BaseUploadFileWorker.java => upload/BaseUploadWorker.java} (60%) create mode 100644 app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => upload}/MediaBackupScannerWorker.java (89%) rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => upload}/UploadFileManuallyWorker.java (57%) rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => upload}/UploadFolderFileAutomaticallyWorker.java (54%) rename app/src/main/java/com/seafile/seadroid2/framework/worker/{ => upload}/UploadMediaFileAutomaticallyWorker.java (55%) diff --git a/app/build.gradle b/app/build.gradle index dfad913f4..47b7899db 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,7 +14,7 @@ android { compileSdk rootProject.ext.compileSdkVersion versionCode 150 - versionName "3.0.0-beta" + versionName "3.0.1-beta" multiDexEnabled true resValue "string", "authorities", defaultConfig.applicationId + '.debug.cameraupload.provider' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4053cdcfb..81ed6c96d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -98,6 +98,11 @@ android:name=".util.GlideCache" android:value="AppGlideModule" /> + + diff --git a/app/src/main/java/com/seafile/seadroid2/config/Constants.java b/app/src/main/java/com/seafile/seadroid2/config/Constants.java index fe0f3688f..57f4942f9 100644 --- a/app/src/main/java/com/seafile/seadroid2/config/Constants.java +++ b/app/src/main/java/com/seafile/seadroid2/config/Constants.java @@ -8,10 +8,8 @@ private Constants() { throw new IllegalStateException("Constants class"); //NON-NLS(1) } - public static final String APP_PACKAGE = "com.seafile.seadroid2"; - - public static final int PERIODIC_SCAN_INTERVALS = 1000 * 60 * 30; //30 mins + public static final int PERIODIC_SCAN_INTERVALS = 1000 * 60 * 5; //5m public static final int PASSWORD_MINIMUM_LENGTH = 8; public static final String URL_PRIVACY = "https://www.seafile.com/privacy/"; diff --git a/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java b/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java index 34334eb5e..68c6e558a 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/data/db/dao/FileTransferDAO.java @@ -81,30 +81,37 @@ public interface FileTransferDAO { @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = :transfer_action and is_auto_transfer = 1 and transfer_status in ('IN_PROGRESS', 'WAITING') and data_source = :feature and data_status = 0 order by created_at asc limit 1") List getOnePendingTransferSync(String related_account, TransferAction transfer_action, TransferDataSource feature); - @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = :transfer_action and is_auto_transfer = 1 and transfer_status in ('IN_PROGRESS', 'WAITING') and data_status = 0 order by created_at asc limit :limit") - List getListPendingTransferSync(String related_account, TransferAction transfer_action, int limit); + @Query("select COUNT(*) from file_transfer_list where related_account = :related_account and transfer_action = :transfer_action and is_auto_transfer = 1 and transfer_status in ('IN_PROGRESS', 'WAITING') and data_source = :feature and data_status = 0") + int countPendingTransferSync(String related_account, TransferAction transfer_action, TransferDataSource feature); + @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = :transfer_action and is_auto_transfer = 1 and transfer_status in ('IN_PROGRESS', 'WAITING') and data_status = 0 order by created_at asc limit :limit offset :offset") + List getPagePendingListTransferSync(String related_account, TransferAction transfer_action, int limit, int offset); + @Query("select * from file_transfer_list where transfer_action = :transfer_action and is_auto_transfer = 1 and transfer_status in ('IN_PROGRESS', 'WAITING') and data_source = :feature and data_status = 0 order by created_at asc limit 1") List getOnePendingTransferAllAccountSync(TransferAction transfer_action, TransferDataSource feature); - @Query("select * from file_transfer_list where related_account = :related_account and is_auto_transfer = 1 and transfer_action = 'DOWNLOAD' and transfer_status in ('IN_PROGRESS', 'WAITING') and data_status = 0 order by created_at asc limit 10") - List getPendingDownloadListByActionSync(String related_account); - @Query("select * from file_transfer_list where related_account = :related_account and is_auto_transfer = 1 and transfer_action = 'DOWNLOAD' and transfer_status in ('IN_PROGRESS', 'WAITING') and data_status = 0 order by created_at asc limit 1") List getOnePendingDownloadByActionSync(String related_account); - - @Query("select COUNT(*) from file_transfer_list where related_account = :related_account and is_auto_transfer = 1 and transfer_action = 'DOWNLOAD' and transfer_status in ('IN_PROGRESS', 'WAITING') and data_status = 0") + @Query("select COUNT(*) from file_transfer_list where related_account = :related_account and is_auto_transfer = 1 and transfer_action = 'DOWNLOAD' and transfer_status in ('IN_PROGRESS', 'WAITING') and data_status = 0") int countPendingDownloadListSync(String related_account); @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = 'UPLOAD' and data_source in ('FOLDER_BACKUP','FILE_BACKUP','ALBUM_BACKUP') and data_status = 0 order by created_at desc") Single> getUploadListAsync(String related_account); + @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = 'UPLOAD' and data_source in ('FOLDER_BACKUP','FILE_BACKUP','ALBUM_BACKUP') and data_status = 0 order by created_at desc limit :limit offset :offset") + List getPageUploadListSync(String related_account, int limit, int offset); + + @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = 'DOWNLOAD' and data_status = 0 order by created_at desc") Single> getDownloadListAsync(String related_account); + @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = 'DOWNLOAD' and data_status = 0 order by created_at desc limit :limit offset :offset") + List getPageDownloadListSync(String related_account, int limit, int offset); + + @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = 'DOWNLOAD' and data_status = 0 order by created_at desc") List getDownloadListSync(String related_account); @@ -121,13 +128,16 @@ public interface FileTransferDAO { @Query("select * from file_transfer_list where repo_id = :repoId and full_path IN(:fullPaths) and transfer_action = :transfer_action order by created_at asc") Single> getListByFullPathsAsync(String repoId, List fullPaths, TransferAction transfer_action); - @Query("select * from file_transfer_list where repo_id = :repoId and transfer_action = 'DOWNLOAD' and transfer_result = 'SUCCEEDED' and parent_path = :parent_path order by created_at asc") + @Query("select * from file_transfer_list where repo_id = :repoId and transfer_action = 'DOWNLOAD' and transfer_status = 'SUCCEEDED' and parent_path = :parent_path order by created_at asc") Single> getDownloadedListByParentAsync(String repoId, String parent_path); @Query("select * from file_transfer_list where repo_id = :repoId and full_path IN(:fullPaths) and transfer_action = :transfer_action order by created_at asc") List getListByFullPathsSync(String repoId, List fullPaths, TransferAction transfer_action); + @Query("select * from file_transfer_list where repo_id = :repoId and transfer_action = :transfer_action order by created_at asc limit :limit offset :offset") + List getPageListSync(String repoId, TransferAction transfer_action, int limit, int offset); + @Query("select * from file_transfer_list where related_account = :related_account and transfer_action = :transferAction and full_path = :full_path and data_status = 0 order by created_at") List getListByFullPathSync(String related_account, TransferAction transferAction, String full_path); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataManager.java b/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataManager.java index 97836cf74..f8fd00b69 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataManager.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/datastore/DataManager.java @@ -256,6 +256,26 @@ public static File getLocalRepoFile(Account account, String repoId, String repoN return new File(localPath); } + /** + * Each repo is placed under [account-dir]/[repo-name]. + * When a file is downloaded, it's placed in its repo, with its full path. + */ + public static File getLocalRepoPath(Account account, String repoId, String repoName) throws RuntimeException { + File file = getRepoDirMappingDataStore(account, repoId, repoName); + + + //build valid file path and name + String localPath = com.seafile.seadroid2.framework.util.FileUtils.buildValidFilePathName(file.getAbsolutePath()); + + File parentDir = new File(Utils.getParentPath(localPath)); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + + return new File(localPath); + } + + /** * calculate if refresh time is expired, the expiration is 10 mins */ diff --git a/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/FolderBackupManager.java b/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/FolderBackupManager.java index 1fcc06f5f..592a1a906 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/FolderBackupManager.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/FolderBackupManager.java @@ -5,6 +5,7 @@ import androidx.annotation.Nullable; import com.blankj.utilcode.util.CollectionUtils; +import com.blankj.utilcode.util.EncryptUtils; import com.blankj.utilcode.util.GsonUtils; import com.google.gson.reflect.TypeToken; import com.seafile.seadroid2.account.Account; @@ -113,8 +114,7 @@ public static void writeBackupPaths(List paths) { } public static String readBackupPathStr() { - String confStr = DataStoreManager.getInstanceByUser(getCurrentAccount()).readString(SettingsManager.FOLDERS_BACKUP_SELECTED_PATH_KEY); - return confStr; + return DataStoreManager.getInstanceByUser(getCurrentAccount()).readString(SettingsManager.FOLDERS_BACKUP_SELECTED_PATH_KEY); } public static List readBackupPaths() { @@ -130,6 +130,28 @@ public static List readBackupPaths() { return CollectionUtils.isEmpty(list) ? CollectionUtils.newArrayList() : list; } + public static long readBackupPathLastScanTime(String absPath) { + String k = SettingsManager.FOLDER_BACKUP_LAST_TIME_PREFIX + EncryptUtils.encryptMD5ToString(absPath); + return DataStoreManager + .getInstanceByUser(getCurrentAccount()) + .readLong(k); + } + + public static void writeBackupPathLastScanTime(String absPath) { + String k = SettingsManager.FOLDER_BACKUP_LAST_TIME_PREFIX + EncryptUtils.encryptMD5ToString(absPath); + + DataStoreManager + .getInstanceByUser(getCurrentAccount()) + .writeLong(k, System.currentTimeMillis()); + } + + public static void clearBackupPathLastScanTime(String absPath) { + String k = SettingsManager.FOLDER_BACKUP_LAST_TIME_PREFIX + EncryptUtils.encryptMD5ToString(absPath); + + DataStoreManager + .getInstanceByUser(getCurrentAccount()) + .removeByKey(k); + } public static void writeSkipHiddenFiles(boolean isSkip) { DataStoreManager.getInstanceByUser(getCurrentAccount()).writeBoolean(SettingsManager.FOLDER_BACKUP_SKIP_HIDDEN_FILES, isSkip); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/SettingsManager.java b/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/SettingsManager.java index 457a3934e..7a0cd636e 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/SettingsManager.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/datastore/sp/SettingsManager.java @@ -75,8 +75,17 @@ public final class SettingsManager { public static final String FOLDER_BACKUP_STATE = gAppContext.getString(R.string.key_folder_backup_state); public static final String FOLDER_BACKUP_PATHS = "folder_backup_paths"; + + /** + * The last time the folder backup service was executed + */ public static final String FOLDER_BACKUP_LAST_TIME = "folder_backup_last_time"; + /** + * The last sync time for each backup folder + */ + public static final String FOLDER_BACKUP_LAST_TIME_PREFIX = "folder_backup_last_time_"; + /** * Is it necessary to filter hidden files when the folder backup service is turned on */ diff --git a/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java b/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java index ac8e0c71b..1cfbf7e37 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/file_monitor/FileSyncService.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import com.blankj.utilcode.util.CollectionUtils; +import com.blankj.utilcode.util.NetworkUtils; import com.seafile.seadroid2.framework.datastore.DataManager; import com.seafile.seadroid2.framework.datastore.StorageManager; import com.seafile.seadroid2.framework.util.SLogs; @@ -19,7 +20,6 @@ import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; import org.apache.commons.io.monitor.FileAlterationListener; -import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; import java.io.File; @@ -117,10 +117,23 @@ public void onCreate() { //file upload backup BackgroundJobManagerImpl.getInstance().startFileUploadWorker(); - - startFolderMonitor(); + if (!NetworkUtils.isRegisteredNetworkStatusChangedListener(networkStatusChangedListener)) { + NetworkUtils.registerNetworkStatusChangedListener(networkStatusChangedListener); + } } + private final NetworkUtils.OnNetworkStatusChangedListener networkStatusChangedListener = new NetworkUtils.OnNetworkStatusChangedListener() { + @Override + public void onDisconnected() { + SLogs.e("disconnected: " + NetworkUtils.getNetworkType()); + } + + @Override + public void onConnected(NetworkUtils.NetworkType networkType) { + SLogs.e("connected: " + networkType); + } + }; + private final FileFilter FILE_FILTER = file -> { if (file.getAbsolutePath().startsWith(TEMP_FILE_DIR)) { @@ -147,7 +160,7 @@ public void stopFolderMonitor() { } } - private void startFolderMonitor() { + public void startFolderMonitor() { List pathList = FolderBackupManager.readBackupPaths(); boolean isFound = pathList.stream().anyMatch(IGNORE_PATHS::contains); @@ -159,7 +172,7 @@ private void startFolderMonitor() { startFolderMonitor(pathList); } - public void startFolderMonitor(List pathList) { + private void startFolderMonitor(List pathList) { if (CollectionUtils.isEmpty(pathList)) { return; } @@ -199,7 +212,7 @@ public void doBackup(String action, File file) { // The file has changed: /storage/emulated/0/Android/media/com.seafile.seadroid2/Seafile if (file.getAbsolutePath().startsWith(IGNORE_PATHS.get(0))) { if ("change".equals(action)) { - BackgroundJobManagerImpl.getInstance().startDownloadCheckerWorker(file.getAbsolutePath()); + BackgroundJobManagerImpl.getInstance().startDownloadedCheckerWorker(file.getAbsolutePath()); } } else { BackgroundJobManagerImpl.getInstance().scheduleFolderBackupScannerWorker(true); @@ -273,6 +286,10 @@ public void onDestroy() { if (mediaContentObserver != null) { mediaContentObserver.unregister(); } + + if (NetworkUtils.isRegisteredNetworkStatusChangedListener(networkStatusChangedListener)) { + NetworkUtils.unregisterNetworkStatusChangedListener(networkStatusChangedListener); + } } } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/http/BaseIO.java b/app/src/main/java/com/seafile/seadroid2/framework/http/BaseIO.java index 26e9dcd0b..2a4e9043a 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/http/BaseIO.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/http/BaseIO.java @@ -35,7 +35,7 @@ public abstract class BaseIO { - private final int DEFAULT_TIME_OUT = 60000; + private final int DEFAULT_TIME_OUT = 120000; private final File cachePath = SeadroidApplication.getAppContext().getCacheDir(); //cache path @@ -158,43 +158,44 @@ public OkHttpClient getClient() { if (okHttpClient == null) { synchronized (BaseIO.class) { if (okHttpClient == null) { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + try { // Install the all-trusting trust manager - final SSLContext sslContext = SSLContext.getInstance("SSL"); + final SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); // Create an ssl socket factory with our all-trusting manager final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); - - OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]); - builder.connectionSpecs(Arrays.asList( - ConnectionSpec.MODERN_TLS, - ConnectionSpec.COMPATIBLE_TLS, - ConnectionSpec.CLEARTEXT)); - builder.cache(cache); - - //cache control - builder.interceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR); - builder.networkInterceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR); - - //add interceptors - List interceptors = getInterceptors(); - if (interceptors != null && !interceptors.isEmpty()) { - for (Interceptor i : interceptors) { - builder.interceptors().add(i); - } - } - - //timeout - builder.writeTimeout(DEFAULT_TIME_OUT, TimeUnit.MILLISECONDS); - builder.readTimeout(DEFAULT_TIME_OUT, TimeUnit.MILLISECONDS); - builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.MILLISECONDS); - - okHttpClient = builder.build(); } catch (Exception e) { e.printStackTrace(); } + + builder.connectionSpecs(Arrays.asList( + ConnectionSpec.MODERN_TLS, + ConnectionSpec.COMPATIBLE_TLS, + ConnectionSpec.CLEARTEXT)); + builder.cache(cache); + + //cache control + builder.interceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR); + builder.networkInterceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR); + + //add interceptors + List interceptors = getInterceptors(); + if (interceptors != null && !interceptors.isEmpty()) { + for (Interceptor i : interceptors) { + builder.interceptors().add(i); + } + } + + //timeout + builder.writeTimeout(DEFAULT_TIME_OUT, TimeUnit.MILLISECONDS); + builder.readTimeout(DEFAULT_TIME_OUT, TimeUnit.MILLISECONDS); + builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.MILLISECONDS); + + okHttpClient = builder.build(); } } } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupNotificationHelper.java index 3a6626874..a9f8b663d 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupNotificationHelper.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupNotificationHelper.java @@ -24,10 +24,13 @@ public Intent getTransferIntent() { } @Override - public String getNotificationTitle() { - String uploading = context.getString(R.string.uploading); - String title = context.getString(R.string.settings_camera_upload_info_title); - return title + " " + uploading; + public String getDefaultTitle() { + return context.getString(R.string.settings_camera_upload_info_title); + } + + @Override + public String getDefaultSubtitle() { + return context.getString(R.string.uploading); } @Override diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupScanNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupScanNotificationHelper.java new file mode 100644 index 000000000..b31c4cb0b --- /dev/null +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/AlbumBackupScanNotificationHelper.java @@ -0,0 +1,44 @@ +package com.seafile.seadroid2.framework.notification; + +import android.content.Context; +import android.content.Intent; + +import com.seafile.seadroid2.R; +import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; +import com.seafile.seadroid2.framework.notification.base.NotificationUtils; + +public class AlbumBackupScanNotificationHelper extends BaseTransferNotificationHelper { + public AlbumBackupScanNotificationHelper(Context context) { + super(context); + } + + @Override + public Intent getTransferIntent() { + return null; + } + + @Override + public String getDefaultTitle() { + return context.getString(R.string.settings_camera_upload_info_title); + } + + @Override + public String getDefaultSubtitle() { + return context.getString(R.string.is_scanning); + } + + @Override + public int getMaxProgress() { + return 0; + } + + @Override + public String getChannelId() { + return NotificationUtils.NOTIFICATION_CHANNEL_TRANSFER; + } + + @Override + public int getNotificationId() { + return NotificationUtils.NOTIFICATION_ID_UPLOAD_ALBUM_BACKUP_SCAN; + } +} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/DownloadNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/DownloadNotificationHelper.java index 76d85b569..959be000f 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/DownloadNotificationHelper.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/DownloadNotificationHelper.java @@ -26,7 +26,12 @@ public Intent getTransferIntent() { } @Override - public String getNotificationTitle() { + public String getDefaultTitle() { + return context.getString(R.string.download); + } + + @Override + public String getDefaultSubtitle() { return context.getString(R.string.downloading); } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/FileBackupNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/FileBackupNotificationHelper.java index fa19db61f..fb2b0bb7a 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/FileBackupNotificationHelper.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/FileBackupNotificationHelper.java @@ -6,6 +6,8 @@ import android.content.Context; import android.content.Intent; +import androidx.work.ForegroundInfo; + import com.seafile.seadroid2.R; import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; import com.seafile.seadroid2.framework.notification.base.NotificationUtils; @@ -24,10 +26,13 @@ public Intent getTransferIntent() { } @Override - public String getNotificationTitle() { - String uploading = context.getString(R.string.uploading); - String title = context.getString(R.string.settings_folder_backup_info_title); - return title + " " + uploading; + public String getDefaultTitle() { + return context.getString(R.string.settings_folder_backup_info_title); + } + + @Override + public String getDefaultSubtitle() { + return context.getString(R.string.uploading); } @Override diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupNotificationHelper.java index 45f5cbb28..234b650c2 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupNotificationHelper.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupNotificationHelper.java @@ -24,10 +24,13 @@ public Intent getTransferIntent() { } @Override - public String getNotificationTitle() { - String uploading = context.getString(R.string.uploading); - String title = context.getString(R.string.settings_folder_backup_info_title); - return title + " " + uploading; + public String getDefaultTitle() { + return context.getString(R.string.settings_folder_backup_info_title); + } + + @Override + public String getDefaultSubtitle() { + return context.getString(R.string.uploading); } @Override diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupScanNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupScanNotificationHelper.java new file mode 100644 index 000000000..4bd72efd2 --- /dev/null +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/FolderBackupScanNotificationHelper.java @@ -0,0 +1,44 @@ +package com.seafile.seadroid2.framework.notification; + +import android.content.Context; +import android.content.Intent; + +import com.seafile.seadroid2.R; +import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; +import com.seafile.seadroid2.framework.notification.base.NotificationUtils; + +public class FolderBackupScanNotificationHelper extends BaseTransferNotificationHelper { + public FolderBackupScanNotificationHelper(Context context) { + super(context); + } + + @Override + public Intent getTransferIntent() { + return null; + } + + @Override + public String getDefaultTitle() { + return context.getString(R.string.settings_folder_backup_info_title); + } + + @Override + public String getDefaultSubtitle() { + return context.getString(R.string.is_scanning); + } + + @Override + public int getMaxProgress() { + return 0; + } + + @Override + public String getChannelId() { + return NotificationUtils.NOTIFICATION_CHANNEL_TRANSFER; + } + + @Override + public int getNotificationId() { + return NotificationUtils.NOTIFICATION_ID_UPLOAD_FOLDER_SCAN; + } +} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/GeneralNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/GeneralNotificationHelper.java index 4b08591bb..6c6e3b868 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/GeneralNotificationHelper.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/GeneralNotificationHelper.java @@ -65,6 +65,14 @@ public void showErrorNotification(String title, String content) { super.showNotification(NotificationUtils.NOTIFICATION_ID_ERROR, title, content, null); } + public void showErrorNotification(@StringRes int titleRes, String content) { + super.showNotification(NotificationUtils.NOTIFICATION_ID_ERROR, context.getString(titleRes), content, null); + } + + public void showErrorNotification(String title, @StringRes int contentRes) { + super.showNotification(NotificationUtils.NOTIFICATION_ID_ERROR, title, context.getString(contentRes), null); + } + public void showErrorNotification(@StringRes int titleRes, @StringRes int contentRes, Intent intent) { super.showNotification(NotificationUtils.NOTIFICATION_ID_ERROR, context.getString(titleRes), context.getString(contentRes), intent); } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/UploadNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/UploadNotificationHelper.java deleted file mode 100644 index d31a0fa98..000000000 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/UploadNotificationHelper.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.seafile.seadroid2.framework.notification; - -import static com.seafile.seadroid2.framework.notification.base.NotificationUtils.NOTIFICATION_MESSAGE_KEY; -import static com.seafile.seadroid2.framework.notification.base.NotificationUtils.NOTIFICATION_OPEN_UPLOAD_TAB; - -import android.content.Context; -import android.content.Intent; - -import com.seafile.seadroid2.R; -import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; -import com.seafile.seadroid2.framework.notification.base.NotificationUtils; -import com.seafile.seadroid2.ui.transfer_list.TransferActivity; - -public class UploadNotificationHelper extends BaseTransferNotificationHelper { - public UploadNotificationHelper(Context context) { - super(context); - } - - @Override - public Intent getTransferIntent() { - Intent dIntent = new Intent(context, TransferActivity.class); - dIntent.putExtra(NOTIFICATION_MESSAGE_KEY, NOTIFICATION_OPEN_UPLOAD_TAB); - return dIntent; - } - - @Override - public String getNotificationTitle() { - return context.getString(R.string.notification_upload_started_title); - } - - @Override - public int getMaxProgress() { - return 100; - } - - @Override - public String getChannelId() { - return NotificationUtils.NOTIFICATION_CHANNEL_TRANSFER; - } - - @Override - public int getNotificationId() { - return NotificationUtils.NOTIFICATION_ID_UPLOAD; - } -} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseNotification.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseNotification.java index 57e0ebe8a..7e1707778 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseNotification.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseNotification.java @@ -2,16 +2,19 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE; +import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.pm.ServiceInfo; import android.os.Build; import androidx.activity.contextaware.ContextAware; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; +import androidx.work.ForegroundInfo; import com.seafile.seadroid2.R; @@ -27,7 +30,6 @@ public abstract class BaseNotification { protected Context context; private long last_time = 0; - public abstract String getChannelId(); public abstract int getMaxProgress(); @@ -67,7 +69,6 @@ private void init() { } } - public void showNotification(int nid, String title, String content, Intent intent) { if (!hasPermission) { return; @@ -115,6 +116,54 @@ public void notifyProgress(int nid, String title, String subTitle, int percent, showNotification(nid, title, text, intent); } + public ForegroundInfo getForegroundProgressNotification(int nid, String title, String subTitle, int percent, int totalCount, Intent intent) { + if (!hasPermission) { + return null; + } + + long now = System.currentTimeMillis(); + if (now - last_time < 1000) { + return null; + } + last_time = now; + + builder.setProgress(getMaxProgress(), percent, false); + + if (totalCount > 0) { + subTitle = subTitle + " / " + totalCount; + } + + String progressStr = context.getString(R.string.notification_upload_upload_in_progress); + String text = String.format(progressStr, percent, subTitle); + + return getForegroundNotification(nid, title, text, intent); + } + + public ForegroundInfo getForegroundNotification(int nid, String title, String content, Intent intent) { + if (!hasPermission) { + return null; + } + + builder.setContentTitle(title); + builder.setContentText(content); + + if (null == intent) { + builder.setContentIntent(null); + } else { + PendingIntent pendingIntent = PendingIntent.getActivity(context, + REQ_CODE, + intent, + FLAG_IMMUTABLE); + builder.setContentIntent(pendingIntent); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + return new ForegroundInfo(nid, builder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); + } else { + return new ForegroundInfo(nid, builder.build()); + } + } + //////////////// /// cancel //////////////// diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseTransferNotificationHelper.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseTransferNotificationHelper.java index f51c159ca..d6b92be7f 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseTransferNotificationHelper.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/base/BaseTransferNotificationHelper.java @@ -4,6 +4,7 @@ import android.content.Intent; import androidx.annotation.StringRes; +import androidx.work.ForegroundInfo; import com.seafile.seadroid2.R; @@ -11,7 +12,9 @@ public abstract class BaseTransferNotificationHelper extends BaseNotification { public abstract Intent getTransferIntent(); - public abstract String getNotificationTitle(); + public abstract String getDefaultTitle(); + + public abstract String getDefaultSubtitle(); public abstract String getChannelId(); @@ -21,29 +24,60 @@ protected BaseTransferNotificationHelper(Context context) { super(context); } - public void showNotification() { - super.showNotification(getNotificationId(), getNotificationTitle(), null, getTransferIntent()); +// +// public void showNotification() { +// super.showNotification(getNotificationId(), getDefaultTitle(), getDefaultSubtitle(), getTransferIntent()); +// } +// +// public void showNotification(String title) { +// super.showNotification(getNotificationId(), title, getDefaultSubtitle(), getTransferIntent()); +// } +// +// public void showNotification(@StringRes int titleRes) { +// super.showNotification(getNotificationId(), context.getString(titleRes), getDefaultSubtitle(), getTransferIntent()); +// } +// +// public void showNotification(@StringRes int titleRes, @StringRes int contentRes) { +// super.showNotification(getNotificationId(), context.getString(titleRes), context.getString(contentRes), getTransferIntent()); +// } + + public void notifyProgress(String fileName, int percent) { + super.notifyProgress(getNotificationId(), fileName, getDefaultTitle(), percent, getTransferIntent()); } - public void showNotification(String title) { - super.showNotification(getNotificationId(), title, context.getString(R.string.wait), getTransferIntent()); + public void notifyProgress(String fileName, int percent, int totalCount) { + super.notifyProgress(getNotificationId(), fileName, getDefaultSubtitle(), percent, totalCount, getTransferIntent()); } - public void showNotification(@StringRes int titleRes) { - String title = context.getString(titleRes); - super.showNotification(getNotificationId(), title, context.getString(R.string.wait), getTransferIntent()); + + //Foreground Notification + public ForegroundInfo getForegroundNotification() { + return super.getForegroundNotification(getNotificationId(), getDefaultTitle(), getDefaultSubtitle(), getTransferIntent()); } - public void showNotification(@StringRes int titleRes, @StringRes int contentRes) { - super.showNotification(getNotificationId(), context.getString(titleRes), context.getString(contentRes), getTransferIntent()); + public ForegroundInfo getForegroundNotification(String title) { + return super.getForegroundNotification(getNotificationId(), title, getDefaultSubtitle(), getTransferIntent()); } - public void notifyProgress(String fileName, int percent) { - super.notifyProgress(getNotificationId(), fileName, getNotificationTitle(), percent, getTransferIntent()); + public ForegroundInfo getForegroundNotification(String title, String content) { + return super.getForegroundNotification(getNotificationId(), title, content, getTransferIntent()); } - public void notifyProgress(String fileName, int percent, int totalCount) { - super.notifyProgress(getNotificationId(), fileName, getNotificationTitle(), percent,totalCount, getTransferIntent()); + public ForegroundInfo getForegroundNotification(@StringRes int titleRes) { + return super.getForegroundNotification(getNotificationId(), context.getString(titleRes), getDefaultSubtitle(), getTransferIntent()); + } + + public ForegroundInfo getForegroundNotification(@StringRes int titleRes, @StringRes int contentRes) { + return super.getForegroundNotification(getNotificationId(), context.getString(titleRes), context.getString(contentRes), getTransferIntent()); + } + + //Progress Foreground Notification + public ForegroundInfo getForegroundProgressNotification(String fileName, int percent) { + return super.getForegroundProgressNotification(getNotificationId(), fileName, getDefaultSubtitle(), percent, 0, getTransferIntent()); + } + + public ForegroundInfo getForegroundProgressNotification(String fileName, int percent, int totalCount) { + return super.getForegroundProgressNotification(getNotificationId(), fileName, getDefaultSubtitle(), percent, totalCount, getTransferIntent()); } public void cancel() { diff --git a/app/src/main/java/com/seafile/seadroid2/framework/notification/base/NotificationUtils.java b/app/src/main/java/com/seafile/seadroid2/framework/notification/base/NotificationUtils.java index 0781d2824..798a407f0 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/notification/base/NotificationUtils.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/notification/base/NotificationUtils.java @@ -23,11 +23,16 @@ public class NotificationUtils { public static final int NOTIFICATION_ID_GENERAL = 1010; public static final int NOTIFICATION_ID_DOWNLOAD = 2000; - @Deprecated - public static final int NOTIFICATION_ID_UPLOAD = 3000; - public static final int NOTIFICATION_ID_UPLOAD_FOLDER = 3010; + //folder + public static final int NOTIFICATION_ID_UPLOAD_FOLDER_SCAN = 3010; + public static final int NOTIFICATION_ID_UPLOAD_FOLDER = 3011; public static final int NOTIFICATION_ID_UPLOAD_FILE = 3011; + + //album public static final int NOTIFICATION_ID_UPLOAD_ALBUM_BACKUP = 3020; + public static final int NOTIFICATION_ID_UPLOAD_ALBUM_BACKUP_SCAN = 3021; + + public static final int NOTIFICATION_ID_OPEN_APK = 4000; diff --git a/app/src/main/java/com/seafile/seadroid2/framework/util/Objs.java b/app/src/main/java/com/seafile/seadroid2/framework/util/Objs.java index 47cb15fd5..c4659c2e0 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/util/Objs.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/util/Objs.java @@ -47,14 +47,18 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.TreeMap; import java.util.stream.Collectors; import io.reactivex.Completable; import io.reactivex.Single; +import io.reactivex.SingleEmitter; +import io.reactivex.SingleOnSubscribe; import io.reactivex.SingleSource; import io.reactivex.functions.BiFunction; import io.reactivex.functions.Function; @@ -97,7 +101,7 @@ public SingleSource> apply(List starredModels) //////////////////////////// //////repo //////////////////////////// - public static Single> getReposSingleFromServer( Account account) { + public static Single> getReposSingleFromServer(Account account) { Single netSingle = IO.getInstanceByAccount(account).execute(RepoService.class).getRepos(); Single> dbListSingle = AppDatabase.getInstance().repoDao().getListByAccount(account.getSignature()); @@ -446,15 +450,22 @@ public SingleSource> apply(List direntModels) thr @Override public SingleSource> apply(List fileTransferEntities) throws Exception { + Map transferMap = new HashMap<>(fileTransferEntities.size()); + for (FileTransferEntity fileTransferEntity : fileTransferEntities) { + transferMap.put(fileTransferEntity.full_path, fileTransferEntity); + } + for (DirentModel direntModel : direntModels) { String fullPath = direntModel.parent_dir + direntModel.name; - Optional firstOp = fileTransferEntities.stream().filter(f -> TextUtils.equals(fullPath, f.full_path)).findFirst(); - if (firstOp.isPresent()) { - FileTransferEntity entity = firstOp.get(); - if (entity.transfer_status == TransferStatus.SUCCEEDED) { - direntModel.transfer_status = entity.transfer_status; - direntModel.local_file_path = entity.target_path; - } + + if (!transferMap.containsKey(fullPath)) { + continue; + } + + FileTransferEntity entity = transferMap.get(fullPath); + if (entity.transfer_status == TransferStatus.SUCCEEDED) { + direntModel.transfer_status = entity.transfer_status; + direntModel.local_file_path = entity.target_path; } } @@ -573,7 +584,7 @@ public int compare(DirentModel o1, DirentModel o2) { newList = list.stream().sorted(new Comparator() { @Override public int compare(DirentModel o1, DirentModel o2) { - return o1.mtime < o2.mtime ? -1 : 1; + return Long.compare(o1.mtime,o2.mtime); } }).collect(Collectors.toList()); break; @@ -581,7 +592,8 @@ public int compare(DirentModel o1, DirentModel o2) { newList = list.stream().sorted(new Comparator() { @Override public int compare(DirentModel o1, DirentModel o2) { - return o1.mtime > o2.mtime ? -1 : 1; + + return -Long.compare(o1.mtime,o2.mtime); } }).collect(Collectors.toList()); break; diff --git a/app/src/main/java/com/seafile/seadroid2/framework/util/TransferUtils.java b/app/src/main/java/com/seafile/seadroid2/framework/util/TransferUtils.java index 3492a065b..074b6929f 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/util/TransferUtils.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/util/TransferUtils.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.SocketTimeoutException; import javax.net.ssl.SSLHandshakeException; @@ -14,7 +15,7 @@ public class TransferUtils { public static TransferResult convertException2TransferResult(Exception e) { if (e instanceof JSONException) { - return TransferResult.NETWORK_CONNECTION; + return TransferResult.ENCODING_EXCEPTION; } else if (e instanceof SeafException) { if (e == SeafException.notFoundException) { return TransferResult.FILE_NOT_FOUND; @@ -35,6 +36,8 @@ public static TransferResult convertException2TransferResult(Exception e) { return TransferResult.ENCODING_EXCEPTION; } else if (e instanceof SSLHandshakeException) { return TransferResult.SSL_EXCEPTION; + } else if (e instanceof SocketTimeoutException) { + return TransferResult.NETWORK_CONNECTION; } else if (e instanceof IOException) { return TransferResult.NETWORK_CONNECTION; } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java index 04753a56c..70a2b80e3 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/BackgroundJobManagerImpl.java @@ -9,12 +9,19 @@ import androidx.work.PeriodicWorkRequest; import androidx.work.WorkInfo; -import com.blankj.utilcode.util.CollectionUtils; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ListenableFuture; import com.seafile.seadroid2.framework.datastore.sp.AlbumBackupManager; import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; import com.seafile.seadroid2.framework.util.SLogs; +import com.seafile.seadroid2.framework.worker.download.DownloadFileScanWorker; +import com.seafile.seadroid2.framework.worker.download.DownloadWorker; +import com.seafile.seadroid2.framework.worker.download.DownloadedFileCheckerWorker; +import com.seafile.seadroid2.framework.worker.upload.FolderBackupScannerWorker; +import com.seafile.seadroid2.framework.worker.upload.MediaBackupScannerWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFileManuallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker; import java.util.List; import java.util.UUID; @@ -212,14 +219,17 @@ public void scheduleFolderBackupScannerWorker(boolean isForce) { SupportWorkManager.getWorkManager().enqueueUniqueWork(workerName, ExistingWorkPolicy.KEEP, request); } - - public void cancelFolderWorker() { - cancelById(FolderBackupScannerWorker.UID); - cancelById(UploadFolderFileAutomaticallyWorker.UID); + public void restartFolderUploadWorker() { + //restart + NetworkType networkType = NetworkType.UNMETERED; + if (FolderBackupManager.readDataPlanAllowed()) { + networkType = NetworkType.CONNECTED; + } + restartFolderUploadWorker(networkType); } public void restartFolderUploadWorker(NetworkType networkType) { - cancelFolderWorker(); + cancelFilesUploadWorker(); Disposable disposable = startWorkerUntilStopped(UploadFolderFileAutomaticallyWorker.UID).subscribe(new Action() { @Override @@ -305,7 +315,7 @@ public void scheduleOneTimeFilesDownloadScanWorker(String[] direntIds) { public void scheduleOneTimeFilesDownloadScanWorker(String transferId) { Data data = new Data.Builder() - .putString(DownloadFileScanWorker.DATA_TRANSFER_KEY, transferId) + .putString(DownloadFileScanWorker.DATA_TRANSFER_ID_KEY, transferId) .build(); OneTimeWorkRequest request = oneTimeRequestBuilder(DownloadFileScanWorker.class) @@ -329,7 +339,7 @@ public void startFileDownloadWorker() { SupportWorkManager.getWorkManager().enqueueUniqueWork(workerName, ExistingWorkPolicy.KEEP, request); } - public void startDownloadCheckerWorker(String filePath) { + public void startDownloadedCheckerWorker(String filePath) { Data data = new Data.Builder() .putString(DownloadedFileCheckerWorker.FILE_CHANGE_KEY, filePath) .build(); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseDownloadFileWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseDownloadFileWorker.java deleted file mode 100644 index 3f588bbb6..000000000 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseDownloadFileWorker.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.seafile.seadroid2.framework.worker; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.work.WorkerParameters; - -import com.seafile.seadroid2.framework.data.db.AppDatabase; -import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; -import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; -import com.seafile.seadroid2.framework.util.TransferUtils; - -public abstract class BaseDownloadFileWorker extends TransferWorker { - BaseDownloadFileWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - } - - - protected void catchExceptionAndUpdateDB(FileTransferEntity transferEntity, Exception e) { - - transferEntity.transfer_status = TransferStatus.FAILED; - transferEntity.action_end_at = System.currentTimeMillis(); - - transferEntity.transfer_result = TransferUtils.convertException2TransferResult(e); - - AppDatabase.getInstance().fileTransferDAO().update(transferEntity); - } -} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseWorker.java index 7476ae600..207afeb5b 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseWorker.java @@ -15,7 +15,7 @@ public abstract class BaseWorker extends Worker { private final Account currentAccount; - BaseWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + protected BaseWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); currentAccount = SupportAccountManager.getInstance().getCurrentAccount(); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorkerBak.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorkerBak.java deleted file mode 100644 index d3e553108..000000000 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorkerBak.java +++ /dev/null @@ -1,163 +0,0 @@ -package com.seafile.seadroid2.framework.worker; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.work.Data; -import androidx.work.WorkerParameters; - -import com.blankj.utilcode.util.CloneUtils; -import com.blankj.utilcode.util.CollectionUtils; -import com.blankj.utilcode.util.FileUtils; -import com.seafile.seadroid2.SeafException; -import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.account.SupportAccountManager; -import com.seafile.seadroid2.framework.data.db.AppDatabase; -import com.seafile.seadroid2.framework.data.db.entities.DirentModel; -import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; -import com.seafile.seadroid2.framework.data.model.dirents.DirentFileModel; -import com.seafile.seadroid2.framework.data.model.enums.TransferAction; -import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; -import com.seafile.seadroid2.framework.data.model.enums.TransferResult; -import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; -import com.seafile.seadroid2.framework.notification.FolderBackupNotificationHelper; -import com.seafile.seadroid2.framework.util.SLogs; -import com.seafile.seadroid2.framework.util.Utils; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.UUID; - -/** - * Check the change status of the downloaded file - */ -@Deprecated -public class DownloadedFileCheckerWorkerBak extends BaseUploadFileWorker { - public static final UUID UID = UUID.randomUUID(); - - private final FolderBackupNotificationHelper notificationManager; - - public DownloadedFileCheckerWorkerBak(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - - notificationManager = new FolderBackupNotificationHelper(context); - } - - @Override - public FolderBackupNotificationHelper getNotification() { - return notificationManager; - } - - @NonNull - @Override - public Result doWork() { - return start(); - } - - private Result start() { - notificationManager.cancel(); - - Account account = SupportAccountManager.getInstance().getCurrentAccount(); - if (account == null) { - return Result.success(); - } - - String outEvent = TransferEvent.EVENT_TRANSFERRED_WITH_DATA; - - //get last 10 pending transfer record - List transferedList = AppDatabase.getInstance().fileTransferDAO().getDownloadListSync(account.getSignature()); - if (CollectionUtils.isEmpty(transferedList)) { - return Result.success(); - } - - notificationManager.showNotification(); - - //Send a completion event - Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, outEvent) - .build(); - - for (FileTransferEntity fileTransferEntity : transferedList) { - try { - checkFile(account, fileTransferEntity); - } catch (IOException | SeafException e) { - throw new RuntimeException(e); - } - } - - notificationManager.cancel(); - - return Result.success(data); - } - - private void checkFile(Account account, FileTransferEntity transferEntity) throws IOException, SeafException { - if (transferEntity.transfer_status != TransferStatus.SUCCEEDED) { - SLogs.d("transfer_status is not success: " + transferEntity.target_path); - return; - } - - File file = new File(transferEntity.target_path); - if (!file.exists()) { - SLogs.d("file is not exists: " + transferEntity.target_path); - return; - } - - List direntList = AppDatabase.getInstance().direntDao().getListByFullPathSync(transferEntity.repo_id, transferEntity.full_path); - if (CollectionUtils.isEmpty(direntList)) { - // db not exist - SLogs.d("db is not exists: " + transferEntity.target_path); - return; - } - DirentModel direntModel = direntList.get(0); - - //More judgment conditions may be required - - if (direntModel.last_modified_at == transferEntity.modified_at) { - SLogs.d("modified_at is same: " + transferEntity.target_path); - - return; - } - - if (direntModel.size == transferEntity.file_size) { - SLogs.d("file size is same: " + transferEntity.target_path); - - return; - } - - DirentFileModel fileModel = getRemoteFile(transferEntity.repo_id, transferEntity.full_path); - if (fileModel == null) { - //remote not exists, delete local - SLogs.d("remote file is not exists: " + transferEntity.target_path); - return; - } - - - FileTransferEntity newTransferEntity = CloneUtils.deepClone(transferEntity, FileTransferEntity.class); - newTransferEntity.full_path = transferEntity.target_path; - newTransferEntity.target_path = transferEntity.full_path; - newTransferEntity.setParent_path(Utils.getParentPath(newTransferEntity.target_path)); - newTransferEntity.file_id = null; - newTransferEntity.transfer_action = TransferAction.UPLOAD; - newTransferEntity.transferred_size = 0; - newTransferEntity.transfer_result = TransferResult.NO_RESULT; - newTransferEntity.transfer_status = TransferStatus.WAITING; - newTransferEntity.file_size = FileUtils.getFileLength(newTransferEntity.full_path); - newTransferEntity.file_strategy = ExistingFileStrategy.REPLACE; - newTransferEntity.is_copy_to_local = true; - newTransferEntity.is_auto_transfer = true; - newTransferEntity.data_source = TransferDataSource.FILE_BACKUP; - newTransferEntity.action_end_at = 0; - newTransferEntity.created_at = System.currentTimeMillis(); - newTransferEntity.modified_at = newTransferEntity.created_at; - newTransferEntity.file_original_modified_at = file.lastModified(); - newTransferEntity.file_md5 = FileUtils.getFileMD5ToString(newTransferEntity.full_path).toLowerCase(); - - newTransferEntity.uid = newTransferEntity.getUID(); - - AppDatabase.getInstance().fileTransferDAO().insert(newTransferEntity); - - - BackgroundJobManagerImpl.getInstance().startFileUploadWorker(); - } -} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/FolderBackupScannerWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/FolderBackupScannerWorker.java deleted file mode 100644 index 8dfa2f786..000000000 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/FolderBackupScannerWorker.java +++ /dev/null @@ -1,318 +0,0 @@ -package com.seafile.seadroid2.framework.worker; - -import static com.seafile.seadroid2.config.Constants.PERIODIC_SCAN_INTERVALS; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.text.TextUtils; - -import androidx.annotation.NonNull; -import androidx.room.RoomDatabase; -import androidx.work.Data; -import androidx.work.WorkerParameters; - -import com.blankj.utilcode.util.CollectionUtils; -import com.seafile.seadroid2.R; -import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.account.SupportAccountManager; -import com.seafile.seadroid2.config.Constants; -import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; -import com.seafile.seadroid2.framework.datastore.StorageManager; -import com.seafile.seadroid2.framework.data.db.AppDatabase; -import com.seafile.seadroid2.framework.data.db.entities.RepoModel; -import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; -import com.seafile.seadroid2.framework.data.model.enums.TransferAction; -import com.seafile.seadroid2.framework.data.model.enums.TransferResult; -import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; -import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; -import com.seafile.seadroid2.framework.notification.FolderBackupNotificationHelper; -import com.seafile.seadroid2.framework.util.SLogs; -import com.seafile.seadroid2.framework.util.Utils; -import com.seafile.seadroid2.ui.folder_backup.RepoConfig; - -import java.io.File; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Deque; -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; - - -/** - * Worker Tag: - * - * @see BackgroundJobManagerImpl#TAG_ALL - * @see BackgroundJobManagerImpl#TAG_TRANSFER - */ -public class FolderBackupScannerWorker extends TransferWorker { - public static final UUID UID = UUID.nameUUIDFromBytes(FolderBackupScannerWorker.class.getSimpleName().getBytes()); - - private FolderBackupNotificationHelper notificationHelper; - - public FolderBackupScannerWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - - notificationHelper = new FolderBackupNotificationHelper(context); - } - - @NonNull - @Override - public Result doWork() { - Account account = SupportAccountManager.getInstance().getCurrentAccount(); - if (account == null) { - return Result.success(); - } - - String[] ids = getInputData().getStringArray(TransferWorker.DATA_CANCEL_IDS); - if (ids != null && ids.length > 0) { - - removeFromDB(ids); - - return Result.success(); - } - - - boolean canScan = checkCanScan(); - if (!canScan) { - SLogs.d("UploadFolderBackupScanWorker: do not start the folder scan task this time"); - - return Result.success(); - } - - List backupPaths = FolderBackupManager.readBackupPaths(); - RepoConfig repoConfig = FolderBackupManager.readRepoConfig(); - if (CollectionUtils.isEmpty(backupPaths) || repoConfig == null) { - return Result.success(); - } - - // - String nTitle = getApplicationContext().getString(R.string.settings_folder_backup_info_title); - nTitle += " - " + getApplicationContext().getString(R.string.is_scanning); - - notificationHelper.showNotification(nTitle); - notificationHelper.cancel(3000); - - try { - //send a scan event - sendProgressEvent(TransferEvent.EVENT_SCANNING); - - //do - doBackupPathWork(account, repoConfig, backupPaths); - - } finally { - FolderBackupManager.writeLastScanTime(System.currentTimeMillis()); - - //start upload worker - BackgroundJobManagerImpl.getInstance().startFolderUploadWorker(); - } - - //Send a completion event - Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, TransferEvent.EVENT_SCAN_END) - .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.FILE_BACKUP)) - .build(); - return Result.success(data); - } - - private boolean checkCanScan() { - boolean isOpenBackup = FolderBackupManager.readBackupSwitch(); - if (!isOpenBackup) { - return false; - } - - boolean isForce = getInputData().getBoolean(TransferWorker.DATA_FORCE_TRANSFER_KEY, false); - if (isForce) { - return true; - } - - long lastScanTime = FolderBackupManager.readLastScanTime(); - if (lastScanTime != 0) { - long now = System.currentTimeMillis(); - if (now - lastScanTime < PERIODIC_SCAN_INTERVALS) { - return false; - } - } - - return true; - } - - private void removeFromDB(String[] ids) { -// Removed from the database - List idList = Arrays.asList(ids); - List dbList = AppDatabase.getInstance().fileTransferDAO().getListByUidsSync(idList); - - if (CollectionUtils.isEmpty(dbList)) { - return; - } - - for (FileTransferEntity fileTransferEntity : dbList) { - AppDatabase.getInstance().fileTransferDAO().deleteOne(fileTransferEntity); - } - - // - BackgroundJobManagerImpl.getInstance().startFolderUploadWorker(); - } - - private void doBackupPathWork(Account account, RepoConfig repoConfig, List backupPathsList) { - - List repoModels = AppDatabase.getInstance().repoDao().getByIdSync(repoConfig.getRepoID()); - - if (CollectionUtils.isEmpty(repoModels)) { - return; - } - - RepoModel repoModel = repoModels.get(0); - - for (String backupPath : backupPathsList) { - - //iterate over local files - List localFiles = traverseFiles(backupPath); - if (CollectionUtils.isEmpty(localFiles)) { - continue; - } - - List fullPaths = localFiles.stream().map(File::getAbsolutePath).collect(Collectors.toList()); - List existsList = readExistsListFromDB(repoConfig.getRepoID(), fullPaths); - - List tList = CollectionUtils.newArrayList(); - for (File file : localFiles) { - FileTransferEntity fEntity = FileTransferEntity.convert2ThisForUploadFileSyncWorker(account, repoModel, file, backupPath); - if (fEntity != null) { - tList.add(fEntity); - } - } - - if (CollectionUtils.isEmpty(existsList)) { - AppDatabase.getInstance().fileTransferDAO().insertAll(tList); - continue; - } - - List newList = CollectionUtils.newArrayList(); - - int i = 0; - for (FileTransferEntity transferEntity : tList) { - i++; - Optional optional = existsList.stream().filter(f -> TextUtils.equals(f.full_path, transferEntity.full_path)).findFirst(); - if (!optional.isPresent()) { - newList.add(transferEntity); - SLogs.d(i+" :folder backup scan: new file(local empty): " + transferEntity.target_path); - continue; - } - - FileTransferEntity dbEntity = optional.get(); - if (dbEntity.data_status == Constants.DataStatus.DELETED) { - // has been deleted in db. - SLogs.d(i+" :folder backup scan: skip file(deleted): " + transferEntity.target_path); - - } else if (TextUtils.equals(dbEntity.file_md5, transferEntity.file_md5)) { - //it's the same file,do not insert into db. - SLogs.d(i+" :folder backup scan: skip file(same file): " + transferEntity.target_path); - - } else { - SLogs.d(i+" :folder backup scan: new file: " + transferEntity.target_path); - - transferEntity.transfer_action = TransferAction.UPLOAD; - transferEntity.transfer_result = TransferResult.NO_RESULT; - transferEntity.transfer_status = TransferStatus.WAITING; - transferEntity.file_strategy = ExistingFileStrategy.REPLACE; - newList.add(transferEntity); - } - } - - if (CollectionUtils.isEmpty(newList)) { - AppDatabase.getInstance().fileTransferDAO().insertAll(newList); - } - - } - } - - @SuppressLint("RestrictedApi") - private List readExistsListFromDB(String repoId, List fullPaths) { - List existsList = CollectionUtils.newArrayList(); - -// int pageSize = RoomDatabase.MAX_BIND_PARAMETER_CNT; - int pageSize = 50; - - if (fullPaths.size() > pageSize) { - - //paginate the data - for (int pageNumber = 1; pageNumber <= (fullPaths.size() + pageSize - 1) / pageSize; pageNumber++) { - int fromIndex = (pageNumber - 1) * pageSize; - int toIndex = Math.min(pageNumber * pageSize, fullPaths.size()); - List pageListData = fullPaths.subList(fromIndex, toIndex); - - List tempExistsList = AppDatabase - .getInstance() - .fileTransferDAO() - .getListByFullPathsSync(repoId, pageListData, TransferAction.UPLOAD); - existsList.addAll(tempExistsList); - } - } else { - List tempExistsList = AppDatabase - .getInstance() - .fileTransferDAO() - .getListByFullPathsSync(repoId, fullPaths, TransferAction.UPLOAD); - existsList.addAll(tempExistsList); - } - - return existsList; - } - - private List traverseFiles(String backupPath) { - return traverseFiles(CollectionUtils.newArrayList(backupPath)); - } - - private List traverseFiles(List backupPathsList) { - Deque stack = new ArrayDeque<>(); - - for (String path : backupPathsList) { - stack.push(new File(path)); - } - - //skip folder: /storage/emulated/0/Android/media/com.seafile.seadroid2.debug/ - String lPath = StorageManager.getInstance().getMediaDir().getAbsolutePath(); - lPath = Utils.getParentPath(lPath); - - List filePathList = new ArrayList<>(); - - boolean isSkipHiddenFile = FolderBackupManager.isFolderBackupSkipHiddenFiles(); - - while (!stack.isEmpty()) { - File currentDir = stack.pop(); - File[] files = currentDir.listFiles(); - - if (files == null) { - continue; - } - - for (File file : files) { - if (isSkipHiddenFile) { - if (!file.isHidden()) { - if (file.isDirectory()) { - stack.push(file); - } else { - - String fPath = file.getAbsolutePath(); - if (!fPath.startsWith(lPath)) { - filePathList.add(file); - } - } - } - } else { - if (file.isDirectory()) { - stack.push(file); - } else { - String fPath = file.getAbsolutePath(); - if (!fPath.startsWith(lPath)) { - filePathList.add(file); - } - } - } - } - } - return filePathList; - } -} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java index aa72483f2..6adf0e260 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferEvent.java @@ -1,12 +1,51 @@ package com.seafile.seadroid2.framework.worker; public class TransferEvent { + /** + * scanning + */ public static final String EVENT_SCANNING = "scanning"; + + /** + * a scan-end event
+ * NOTICE: This event will be sent in Result.success(data) instead of in setProgressAsync() + */ public static final String EVENT_SCAN_END = "scan_end"; + + /** + * transferring + */ public static final String EVENT_TRANSFERRING = "transferring"; - public static final String EVENT_TRANSFERRED_WITH_DATA = "transferred_with_data"; - public static final String EVENT_TRANSFERRED_WITHOUT_DATA = "transferred_without_data"; - public static final String EVENT_NOT_TRANSFERRED = "not_transferred"; + /** + * A single file was successfully transferred + */ + public static final String EVENT_TRANSFER_SUCCESS = "transfer_success"; + + /** + * A single file transfer failed + */ + public static final String EVENT_TRANSFER_FAILED = "transfer_failed"; + + /** + * The transfer worker is complete.
+ * NOTICE: This event will be sent in Result.success(data) instead of in setProgressAsync() + */ + public static final String EVENT_FINISH = "transfer_finish_with_data"; + + /** + * The transfer task is complete and no data is uploaded + */ + public static final String EVENT_FINISH_WITHOUT_DATA = "transfer_finish_without_data"; + + /** + * because of an OUT_OF_QUOTA error, the current upload worker was canceled + */ public static final String EVENT_CANCEL_OUT_OF_QUOTA = "transfer_cancel_with_out_of_quota"; + + /** + * because of an NETWORK error, the current upload worker was canceled + */ + public static final String EVENT_CANCEL_WITH_NETWORK_ERR = "transfer_cancel_with_network_err"; + } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferWorker.java index 21378b844..2bf0ac825 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/TransferWorker.java @@ -4,40 +4,47 @@ import androidx.annotation.NonNull; import androidx.work.Data; +import androidx.work.ForegroundInfo; import androidx.work.WorkerParameters; +import com.google.common.util.concurrent.ListenableFuture; import com.seafile.seadroid2.SeafException; import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.framework.data.BlockInfoBean; +import com.seafile.seadroid2.framework.data.db.AppDatabase; +import com.seafile.seadroid2.framework.data.db.entities.DirentModel; +import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; +import com.seafile.seadroid2.framework.data.db.entities.RepoModel; import com.seafile.seadroid2.framework.data.model.dirents.DirentDirModel; import com.seafile.seadroid2.framework.data.model.dirents.DirentFileModel; import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; -import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; +import com.seafile.seadroid2.framework.data.model.repo.DirentWrapperModel; import com.seafile.seadroid2.framework.http.IO; import com.seafile.seadroid2.framework.notification.GeneralNotificationHelper; import com.seafile.seadroid2.framework.util.HttpUtils; +import com.seafile.seadroid2.framework.util.Objs; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.ui.file.FileService; +import com.seafile.seadroid2.ui.repo.RepoService; import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.HashMap; import java.util.LinkedList; +import java.util.List; import java.util.Map; -import io.reactivex.disposables.CompositeDisposable; import okhttp3.RequestBody; public abstract class TransferWorker extends BaseWorker { - public static final int SEGMENT_SIZE = 8192; + public static final String KEY_DATA_EVENT = "data_event_key"; public static final String KEY_DATA_TYPE = "data_type_key"; + public static final String KEY_DATA_PARAM = "data_param_key"; public static final String KEY_DATA_PROGRESS = "data_progress_key"; public static final String KEY_DATA_TRANSFERRED_SIZE = "data_transferred_size_key"; @@ -45,7 +52,7 @@ public abstract class TransferWorker extends BaseWorker { public static final String DATA_DIRENT_LIST_KEY = "data_dirent_list_key"; - public static final String DATA_TRANSFER_KEY = "data_transfer_key"; + public static final String DATA_TRANSFER_ID_KEY = "data_transfer_key"; public static final String DATA_TRANSFER_NAME_KEY = "data_transfer_name_key"; public static final String DATA_FORCE_TRANSFER_KEY = "data_transfer_force_key"; @@ -54,7 +61,7 @@ public abstract class TransferWorker extends BaseWorker { private final GeneralNotificationHelper generalNotificationHelper; - TransferWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + public TransferWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); generalNotificationHelper = new GeneralNotificationHelper(context); @@ -64,86 +71,10 @@ public GeneralNotificationHelper getGeneralNotificationHelper() { return generalNotificationHelper; } -// protected CompositeDisposable compositeDisposable = new CompositeDisposable(); -// -// public CompositeDisposable getCompositeDisposable() { -// return compositeDisposable; -// } - - - protected void sendProgressEvent(String event) { - Data data = new Data.Builder() - .putString(KEY_DATA_EVENT, event) - .putInt(KEY_DATA_PROGRESS, 100) - .putLong(KEY_DATA_TRANSFERRED_SIZE, 0) - .putLong(KEY_DATA_TOTAL_SIZE, 0) - .build(); - - setProgressAsync(data); - } - - protected void sendProgress(String fileName, String uid, int percent, long size, long totalSize, TransferDataSource dataSource) { - Data data = new Data.Builder() - .putString(KEY_DATA_EVENT, TransferEvent.EVENT_TRANSFERRING) - .putString(KEY_DATA_TYPE, String.valueOf(dataSource)) - - .putString(DATA_TRANSFER_NAME_KEY, fileName) - .putString(DATA_TRANSFER_KEY, uid) - .putInt(KEY_DATA_PROGRESS, percent) - .putLong(KEY_DATA_TRANSFERRED_SIZE, size) - .putLong(KEY_DATA_TOTAL_SIZE, totalSize) - .build(); - - setProgressAsync(data); - } - - - protected String getFileUploadUrl(String repoId, String target_dir, boolean isUpdate) throws IOException, SeafException { - retrofit2.Response res; - if (isUpdate) { - res = IO.getInstanceWithLoggedIn() - .execute(FileService.class) - .getFileUpdateLink(repoId) - .execute(); - } else { - -// target_dir = StringUtils.removeEnd(target_dir, "/"); - - res = IO.getInstanceWithLoggedIn() - .execute(FileService.class) - .getFileUploadLink(repoId, "/") - .execute(); - } - - if (!res.isSuccessful()) { - throw new SeafException(res.code(),res.message()); + public void showForegroundAsync(ForegroundInfo foregroundInfo) { + if (foregroundInfo != null) { + setForegroundAsync(foregroundInfo); } - - String urlStr = res.body(); - urlStr = StringUtils.replace(urlStr, "\"", ""); - - return urlStr; - } - - //block - protected BlockInfoBean getFileBlockUploadUrl(Account account, String repoId, LinkedList blkListId) throws IOException, JSONException { - String ids = String.join(",", blkListId); - - Map requestDataMap = new HashMap<>(); - requestDataMap.put("blklist", ids); - - Map requestBodyMap = HttpUtils.generateRequestBody(requestDataMap); - - retrofit2.Response res = IO.getInstanceWithLoggedIn() - .execute(FileService.class) - .getFileBlockUploadLink(repoId, requestBodyMap) - .execute(); - - if (!res.isSuccessful()) { - return null; - } - - return res.body(); } protected boolean checkRemoteDirExists(String repoId, String dirPath) throws IOException { @@ -191,4 +122,105 @@ protected DirentFileModel getRemoteFile(String repoId, String remotePath) throws return fileDetailRes.body(); } + + + protected boolean getRemoteDirentList(Account account, RepoModel repoModel, String parentDir) throws IOException, SeafException { + retrofit2.Response wrapperRes = IO.getInstanceWithLoggedIn() + .execute(RepoService.class) + .getDirentsCall(repoModel.repo_id, parentDir) + .execute(); + + //Successful: code >= 200 && code < 300; + if (!wrapperRes.isSuccessful()) { + throw SeafException.networkException; + } + + DirentWrapperModel direntWrapperModel = wrapperRes.body(); + if (direntWrapperModel == null) { + throw SeafException.networkException; + } + + List direntModels = Objs.parseDirentsForDB( + direntWrapperModel.dirent_list, + direntWrapperModel.dir_id, + account.getSignature(), + repoModel.repo_id, + repoModel.repo_name); + + //delete + AppDatabase.getInstance().direntDao().deleteAllByParentPathSync(repoModel.repo_id, parentDir); + + + //insert + insertAllDataInBatches(direntModels); + return true; + } + + public void insertAllDataInBatches(List data) { + final int batchSize = 1000; + int totalSize = data.size(); + for (int i = 0; i < totalSize; i += batchSize) { + int endIndex = Math.min(totalSize, i + batchSize); + List batchList = data.subList(i, endIndex); + AppDatabase.getInstance().direntDao().insertAllSync(batchList); + } + } + + public void sendEvent(String event, TransferDataSource dataSource) { + sendFutureEvent(event, dataSource); + } + + public ListenableFuture sendFutureEvent(String event, TransferDataSource dataSource) { + Map eventMap = new HashMap<>(); + eventMap.put(KEY_DATA_EVENT, event); + eventMap.put(TransferWorker.KEY_DATA_TYPE, String.valueOf(dataSource)); + return send(eventMap); + } + + public void sendTransferEvent(FileTransferEntity transferEntity, boolean isSuccess) { + Map eventMap = new HashMap<>(); + + eventMap.put(KEY_DATA_TYPE, String.valueOf(transferEntity.data_source)); + + eventMap.put(DATA_TRANSFER_NAME_KEY, transferEntity.file_name); + eventMap.put(DATA_TRANSFER_ID_KEY, transferEntity.uid); + eventMap.put(KEY_DATA_TOTAL_SIZE, transferEntity.file_size); + + if (isSuccess) { + eventMap.put(KEY_DATA_EVENT, TransferEvent.EVENT_TRANSFER_SUCCESS); + + eventMap.put(KEY_DATA_PROGRESS, 100); + eventMap.put(KEY_DATA_TRANSFERRED_SIZE, transferEntity.file_size); + } else { + eventMap.put(KEY_DATA_EVENT, TransferEvent.EVENT_TRANSFER_FAILED); + eventMap.put(KEY_DATA_PROGRESS, 0); + eventMap.put(KEY_DATA_TRANSFERRED_SIZE, 0); + } + + send(eventMap); + } + + public void sendProgressNotifyEvent(String fileName, String uid, int percent, long size, long totalSize, TransferDataSource dataSource) { + Map eventMap = new HashMap<>(); + eventMap.put(KEY_DATA_EVENT, TransferEvent.EVENT_TRANSFERRING); + eventMap.put(KEY_DATA_TYPE, String.valueOf(dataSource)); + + eventMap.put(DATA_TRANSFER_NAME_KEY, fileName); + eventMap.put(DATA_TRANSFER_ID_KEY, uid); + eventMap.put(KEY_DATA_PROGRESS, percent); + eventMap.put(KEY_DATA_TRANSFERRED_SIZE, size); + eventMap.put(KEY_DATA_TOTAL_SIZE, totalSize); + + send(eventMap); + } + + private ListenableFuture send(Map eventData) { + Data.Builder builder = new Data.Builder(); + if (eventData != null) { + builder.putAll(eventData); + } + Data data = builder.build(); + return setProgressAsync(data); + } + } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadWorker.java deleted file mode 100644 index 4f57cffc5..000000000 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadWorker.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.seafile.seadroid2.framework.worker; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.work.Data; -import androidx.work.WorkerParameters; - -import com.blankj.utilcode.util.CollectionUtils; -import com.blankj.utilcode.util.ToastUtils; -import com.seafile.seadroid2.R; -import com.seafile.seadroid2.account.Account; -import com.seafile.seadroid2.account.SupportAccountManager; -import com.seafile.seadroid2.framework.data.db.AppDatabase; -import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; -import com.seafile.seadroid2.framework.data.model.enums.TransferAction; -import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; -import com.seafile.seadroid2.framework.data.model.enums.TransferResult; -import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; -import com.seafile.seadroid2.framework.notification.FolderBackupNotificationHelper; -import com.seafile.seadroid2.framework.notification.UploadNotificationHelper; -import com.seafile.seadroid2.framework.util.SLogs; - -import java.util.List; -import java.util.UUID; - -@Deprecated -public class UploadWorker extends BaseUploadFileWorker { - public static final UUID UID = UUID.randomUUID(); - - private final UploadNotificationHelper notificationManager; - - public UploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - - notificationManager = new UploadNotificationHelper(context); - } - - @Override - public FolderBackupNotificationHelper getNotification() { - return null; - } - - @NonNull - @Override - public Result doWork() { - return start(); - } - - private Result start() { - notificationManager.cancel(); - - Account account = SupportAccountManager.getInstance().getCurrentAccount(); - if (account == null) { - return Result.failure(); - } - - boolean isEnable = FolderBackupManager.readBackupSwitch(); - if (!isEnable) { - return Result.success(); - } - - boolean isUploaded = false; - - notificationManager.showNotification(); - - String outEvent = TransferEvent.EVENT_TRANSFERRED_WITH_DATA; - - while (true) { - SLogs.d("start upload file worker"); - - if (isStopped()) { - return Result.success(); - } - - SLogs.e(account.getSignature()); - - //get last 10 pending transfer record - List transferList = AppDatabase.getInstance().fileTransferDAO() - .getListPendingTransferSync(account.getSignature(), TransferAction.UPLOAD, 10); - - if (CollectionUtils.isEmpty(transferList)) { - break; - } - - try { - boolean isAmple = calcQuota(transferList); - if (!isAmple) { - getGeneralNotificationHelper().showErrorNotification(R.string.above_quota, R.string.settings_folder_backup_info_title); - // - AppDatabase.getInstance().fileTransferDAO().cancel(account.getSignature(), TransferDataSource.FOLDER_BACKUP, TransferResult.OUT_OF_QUOTA); - - outEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; - - break; - } - } catch (Exception e) { - e.printStackTrace(); - break; - } - - isUploaded = true; - for (FileTransferEntity fileTransferEntity : transferList) { - try { - transferFile(account, fileTransferEntity); - } catch (Exception e) { - SLogs.e(e); - catchExceptionAndUpdateDB(fileTransferEntity, e); - } - } - } - - if (isUploaded) { - ToastUtils.showLong(R.string.upload_finished); - SLogs.d("all task run"); - } else { - SLogs.d("nothing to run"); - } - - notificationManager.cancel(); - - //Send a completion event - Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, outEvent) - .build(); - return Result.success(data); - } - -} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/body/ProgressRequestBody.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/body/ProgressRequestBody.java index a52348dbc..cd927150e 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/body/ProgressRequestBody.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/body/ProgressRequestBody.java @@ -19,7 +19,7 @@ public class ProgressRequestBody extends RequestBody { private final File file; private final MediaType mediaType; - private FileTransferProgressListener fileTransferProgressListener; + private final FileTransferProgressListener fileTransferProgressListener; public ProgressRequestBody(File file, FileTransferProgressListener fileTransferProgressListener) { this.file = file; diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java new file mode 100644 index 000000000..0c6480edb --- /dev/null +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/BaseDownloadWorker.java @@ -0,0 +1,108 @@ +package com.seafile.seadroid2.framework.worker.download; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.work.WorkerParameters; + +import com.seafile.seadroid2.R; +import com.seafile.seadroid2.SeafException; +import com.seafile.seadroid2.framework.data.db.AppDatabase; +import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; +import com.seafile.seadroid2.framework.data.model.enums.TransferResult; +import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; +import com.seafile.seadroid2.framework.notification.base.BaseNotification; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; + +import org.json.JSONException; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.SocketTimeoutException; + +import javax.net.ssl.SSLHandshakeException; + +public abstract class BaseDownloadWorker extends TransferWorker { + + public abstract BaseNotification getNotification(); + + public BaseDownloadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + private TransferResult parseTransferException(Exception e) { + if (e instanceof JSONException) { + return TransferResult.ENCODING_EXCEPTION; + } else if (e instanceof SeafException) { + if (e == SeafException.notFoundException) { + return TransferResult.FILE_NOT_FOUND; + } else if (e == SeafException.OUT_OF_QUOTA) { + return TransferResult.OUT_OF_QUOTA; + } else if (e == SeafException.networkException) { + return TransferResult.NETWORK_CONNECTION; + } else if (e == SeafException.sslException) { + return TransferResult.SSL_EXCEPTION; + } else if (e == SeafException.illFormatException) { + return TransferResult.ENCODING_EXCEPTION; + } else if (e == SeafException.notLoggedInException) { + return TransferResult.ACCOUNT_NOT_LOGGED_IN; + } else if (e == SeafException.notFoundUserException) { + return TransferResult.ACCOUNT_NOT_FOUND; + } + } else if (e instanceof UnsupportedEncodingException) { + return TransferResult.ENCODING_EXCEPTION; + } else if (e instanceof SSLHandshakeException) { + return TransferResult.SSL_EXCEPTION; + } else if (e instanceof SocketTimeoutException) { + return TransferResult.NETWORK_CONNECTION; + } else if (e instanceof IOException) { + return TransferResult.NETWORK_CONNECTION; + } + + return TransferResult.UNKNOWN; + } + + public TransferResult onException(FileTransferEntity transferEntity, Exception e) { + transferEntity.transfer_status = TransferStatus.FAILED; + transferEntity.action_end_at = System.currentTimeMillis(); + transferEntity.transfer_result = parseTransferException(e); + + //update db + AppDatabase.getInstance().fileTransferDAO().update(transferEntity); + + return transferEntity.transfer_result; + } + + + public void notifyError(TransferResult result) { + if (result == TransferResult.NETWORK_CONNECTION) { + getGeneralNotificationHelper().showErrorNotification(R.string.network_error, R.string.download); + } else { + getGeneralNotificationHelper().showErrorNotification(String.valueOf(result), R.string.download); + } + } + + public String isInterrupt(TransferResult result) { + String finishFlagEvent = null; + if (result == TransferResult.ENCODING_EXCEPTION) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.FILE_NOT_FOUND) { +// finishFlagEvent = null; + } else if (result == TransferResult.OUT_OF_QUOTA) { + finishFlagEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; + } else if (result == TransferResult.NETWORK_CONNECTION) { + finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_NETWORK_ERR; + } else if (result == TransferResult.SSL_EXCEPTION) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.ACCOUNT_NOT_LOGGED_IN) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.ACCOUNT_NOT_FOUND) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.UNKNOWN) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } + + return finishFlagEvent; + } +} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadFileScanWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadFileScanWorker.java similarity index 94% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadFileScanWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadFileScanWorker.java index 2ed5ad9a1..5775a7558 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadFileScanWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadFileScanWorker.java @@ -1,10 +1,11 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.download; import android.annotation.SuppressLint; import android.content.Context; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.work.ForegroundInfo; import androidx.work.WorkerParameters; import com.blankj.utilcode.util.CollectionUtils; @@ -26,6 +27,8 @@ import com.seafile.seadroid2.framework.http.IO; import com.seafile.seadroid2.framework.notification.DownloadNotificationHelper; import com.seafile.seadroid2.framework.util.SLogs; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.TransferWorker; import com.seafile.seadroid2.ui.file.FileService; import java.io.IOException; @@ -35,7 +38,6 @@ import java.util.List; import java.util.Optional; import java.util.UUID; -import java.util.stream.Collectors; /** @@ -47,12 +49,12 @@ public class DownloadFileScanWorker extends TransferWorker { public static final UUID UID = UUID.nameUUIDFromBytes(DownloadFileScanWorker.class.getSimpleName().getBytes()); - private final DownloadNotificationHelper notificationManager; + private final DownloadNotificationHelper notificationHelper; public DownloadFileScanWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); - notificationManager = new DownloadNotificationHelper(context); + notificationHelper = new DownloadNotificationHelper(context); } @NonNull @@ -64,16 +66,17 @@ public Result doWork() { } // just only for cancel db. - String[] rids = getInputData().getStringArray(DATA_CANCEL_IDS); - String transferId = getInputData().getString(DATA_TRANSFER_KEY); + String[] removeIds = getInputData().getStringArray(DATA_CANCEL_IDS); + String transferId = getInputData().getString(DATA_TRANSFER_ID_KEY); String[] direntIds = getInputData().getStringArray(DATA_DIRENT_LIST_KEY); if (!TextUtils.isEmpty(transferId) || (direntIds != null && direntIds.length > 0)) { - notificationManager.showNotification(R.string.download_waiting); + ForegroundInfo foregroundInfo = notificationHelper.getForegroundNotification(R.string.download_waiting); + showForegroundAsync(foregroundInfo); } - if (rids != null && rids.length > 0) { - removeDownload(rids); + if (removeIds != null && removeIds.length > 0) { + removeDownload(removeIds); } // @@ -121,11 +124,6 @@ public Result doWork() { } } - //dismiss notification - if (!TextUtils.isEmpty(transferId) || (direntIds != null && direntIds.length > 0)) { - notificationManager.cancel(); - } - //start upload worker BackgroundJobManagerImpl.getInstance().startFileDownloadWorker(); @@ -184,7 +182,7 @@ private void insertIntoDbWhenDirentIsFile(Account account, DirentModel direntMod if (!CollectionUtils.isEmpty(existsList)) { FileTransferEntity existEntity = existsList.get(0); - if (TransferStatus.SUCCEEDED == existEntity.transfer_status){ + if (TransferStatus.SUCCEEDED == existEntity.transfer_status) { if (TextUtils.equals(existsList.get(0).file_id, transferEntity.file_id)) { //it's the same file,do not insert into db. SLogs.d("file download: skip file(local exists): " + transferEntity.full_path); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadWorker.java similarity index 87% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadWorker.java index 40e4e6b93..06c6e8dd3 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadWorker.java @@ -1,4 +1,4 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.download; import android.content.Context; import android.text.TextUtils; @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import androidx.work.Data; +import androidx.work.ForegroundInfo; import androidx.work.WorkerParameters; import com.blankj.utilcode.util.CollectionUtils; @@ -18,6 +19,7 @@ import com.seafile.seadroid2.framework.data.Block; import com.seafile.seadroid2.framework.data.db.entities.DirentModel; import com.seafile.seadroid2.framework.data.db.entities.RepoModel; +import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; import com.seafile.seadroid2.framework.datastore.DataManager; import com.seafile.seadroid2.framework.data.FileBlocks; import com.seafile.seadroid2.framework.datastore.StorageManager; @@ -27,7 +29,12 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferResult; import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; import com.seafile.seadroid2.framework.http.IO; +import com.seafile.seadroid2.framework.notification.base.BaseNotification; import com.seafile.seadroid2.framework.util.SLogs; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.ExistingFileStrategy; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import com.seafile.seadroid2.listener.FileTransferProgressListener; import com.seafile.seadroid2.framework.notification.DownloadNotificationHelper; import com.seafile.seadroid2.ui.file.FileService; @@ -55,30 +62,32 @@ * @see BackgroundJobManagerImpl#TAG_ALL * @see BackgroundJobManagerImpl#TAG_TRANSFER */ -public class DownloadWorker extends BaseDownloadFileWorker { +public class DownloadWorker extends BaseDownloadWorker { public static final UUID UID = UUID.nameUUIDFromBytes(DownloadWorker.class.getSimpleName().getBytes()); - private final DownloadNotificationHelper notificationManager; + private final DownloadNotificationHelper notificationHelper; private final FileTransferProgressListener fileTransferProgressListener = new FileTransferProgressListener(); + @Override + public BaseNotification getNotification() { + return notificationHelper; + } + public DownloadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); - notificationManager = new DownloadNotificationHelper(context); + notificationHelper = new DownloadNotificationHelper(context); fileTransferProgressListener.setProgressListener(progressListener); } @Override public void onStopped() { super.onStopped(); - - notificationManager.cancel(); } @NonNull @Override public Result doWork() { - notificationManager.cancel(); Account account = getCurrentAccount(); if (account == null) { @@ -88,13 +97,11 @@ public Result doWork() { //count int pendingCount = AppDatabase.getInstance().fileTransferDAO().countPendingDownloadListSync(account.getSignature()); if (pendingCount <= 0) { - Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA) - .build(); - return Result.success(data); + return Result.success(getFinishData()); } - notificationManager.showNotification(); + ForegroundInfo foregroundInfo = notificationHelper.getForegroundNotification(); + showForegroundAsync(foregroundInfo); //tip String tip = getApplicationContext().getResources().getQuantityString(R.plurals.transfer_download_started, pendingCount, pendingCount); @@ -118,37 +125,47 @@ public Result doWork() { isDownloaded = true; - if (isStopped()) { - break; - } - - FileTransferEntity fileTransferEntity = list.get(0); + FileTransferEntity transferEntity = list.get(0); try { - transferFile(account, fileTransferEntity); + transferFile(account, transferEntity); + + sendTransferEvent(transferEntity, true); + } catch (Exception e) { - catchExceptionAndUpdateDB(fileTransferEntity, e); isDownloaded = false; + + TransferResult transferResult = onException(transferEntity, e); + + // + notifyError(transferResult); + + sendTransferEvent(transferEntity, false); + + String finishFlag = isInterrupt(transferResult); + if (!TextUtils.isEmpty(finishFlag)) { + break; + } } } + SLogs.d("all task run"); + // if (isDownloaded) { ToastUtils.showLong(R.string.download_finished); - SLogs.d("all task run"); - } else { - SLogs.d("nothing to run"); } - notificationManager.cancel(); + return Result.success(getFinishData()); + } - Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, isDownloaded ? TransferEvent.EVENT_TRANSFERRED_WITH_DATA : TransferEvent.EVENT_NOT_TRANSFERRED) + private Data getFinishData() { + return new Data.Builder() + .putString(TransferWorker.KEY_DATA_EVENT, TransferEvent.EVENT_FINISH) + .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.FOLDER_BACKUP)) .build(); - return Result.success(data); } - /** * */ @@ -158,21 +175,25 @@ public void onProgressNotify(FileTransferEntity fileTransferEntity, int percent, SLogs.d(fileTransferEntity.file_name + " -> progress:" + percent); int diff = AppDatabase.getInstance().fileTransferDAO().countPendingDownloadListSync(fileTransferEntity.related_account); - notificationManager.notifyProgress(fileTransferEntity.file_name, percent, diff); + + ForegroundInfo foregroundInfo = notificationHelper.getForegroundProgressNotification(fileTransferEntity.file_name, percent, diff); + showForegroundAsync(foregroundInfo); // AppDatabase.getInstance().fileTransferDAO().update(fileTransferEntity); // - sendProgress(fileTransferEntity.file_name, fileTransferEntity.uid, percent, transferredSize, totalSize, fileTransferEntity.data_source); + sendProgressNotifyEvent(fileTransferEntity.file_name, fileTransferEntity.uid, percent, transferredSize, totalSize, fileTransferEntity.data_source); } }; private void transferFile(Account account, FileTransferEntity transferEntity) throws Exception { SLogs.d("download start:" + transferEntity.full_path); + //show notification int diff = AppDatabase.getInstance().fileTransferDAO().countPendingDownloadListSync(transferEntity.related_account); - notificationManager.notifyProgress(transferEntity.file_name, 0, diff); + ForegroundInfo foregroundInfo = notificationHelper.getForegroundProgressNotification(transferEntity.file_name, 0, diff); + showForegroundAsync(foregroundInfo); List repoModels = AppDatabase.getInstance().repoDao().getByIdSync(transferEntity.repo_id); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadedFileCheckerWorker.java similarity index 89% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadedFileCheckerWorker.java index 5c380efc1..bb059cf4e 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/DownloadedFileCheckerWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/download/DownloadedFileCheckerWorker.java @@ -1,11 +1,11 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.download; -import android.annotation.SuppressLint; import android.content.Context; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.work.Data; +import androidx.work.ForegroundInfo; import androidx.work.WorkerParameters; import com.blankj.utilcode.util.CloneUtils; @@ -25,6 +25,11 @@ import com.seafile.seadroid2.framework.notification.FolderBackupNotificationHelper; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.util.Utils; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.upload.BaseUploadWorker; +import com.seafile.seadroid2.framework.worker.ExistingFileStrategy; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import java.io.File; import java.io.IOException; @@ -34,22 +39,22 @@ /** * Check the change status of the downloaded file */ -public class DownloadedFileCheckerWorker extends BaseUploadFileWorker { +public class DownloadedFileCheckerWorker extends BaseUploadWorker { public static final UUID UID = UUID.nameUUIDFromBytes(DownloadedFileCheckerWorker.class.getSimpleName().getBytes()); public static final String FILE_CHANGE_KEY = "download_file_change_key"; - private final FolderBackupNotificationHelper notificationManager; + private final FolderBackupNotificationHelper notificationHelper; public DownloadedFileCheckerWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); - notificationManager = new FolderBackupNotificationHelper(context); + notificationHelper = new FolderBackupNotificationHelper(context); } @Override public FolderBackupNotificationHelper getNotification() { - return notificationManager; + return notificationHelper; } @NonNull @@ -77,9 +82,8 @@ private Result start() { return Result.success(); } - notificationManager.cancel(); - String outEvent = TransferEvent.EVENT_TRANSFERRED_WITH_DATA; + String outEvent = TransferEvent.EVENT_FINISH; // List transferEntityList = AppDatabase @@ -91,7 +95,8 @@ private Result start() { return Result.success(); } - notificationManager.showNotification(); + ForegroundInfo foregroundInfo = notificationHelper.getForegroundNotification(); + showForegroundAsync(foregroundInfo); try { checkFile(account, transferEntityList.get(0)); @@ -99,8 +104,6 @@ private Result start() { throw new RuntimeException(e); } - notificationManager.cancel(); - //Send a completion event Data data = new Data.Builder() .putString(TransferWorker.KEY_DATA_EVENT, outEvent) @@ -176,7 +179,6 @@ private void checkFile(Account account, FileTransferEntity downloadTransferEntit transferEntity.transfer_status = TransferStatus.WAITING; } - AppDatabase.getInstance().fileTransferDAO().insert(transferEntity); //start diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseUploadFileWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java similarity index 60% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/BaseUploadFileWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java index 4d69ff483..3d2ae3afb 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/BaseUploadFileWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/BaseUploadWorker.java @@ -1,13 +1,15 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.upload; import android.content.Context; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.work.ForegroundInfo; import androidx.work.WorkerParameters; import com.blankj.utilcode.util.CollectionUtils; import com.blankj.utilcode.util.FileUtils; +import com.seafile.seadroid2.R; import com.seafile.seadroid2.SeafException; import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.account.AccountInfo; @@ -30,11 +32,16 @@ import com.seafile.seadroid2.framework.notification.FileBackupNotificationHelper; import com.seafile.seadroid2.framework.notification.FolderBackupNotificationHelper; import com.seafile.seadroid2.framework.notification.base.BaseNotification; +import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; +import com.seafile.seadroid2.framework.util.HttpUtils; import com.seafile.seadroid2.framework.util.SLogs; -import com.seafile.seadroid2.framework.util.TransferUtils; +import com.seafile.seadroid2.framework.worker.ExistingFileStrategy; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import com.seafile.seadroid2.framework.worker.body.ProgressRequestBody; import com.seafile.seadroid2.listener.FileTransferProgressListener; import com.seafile.seadroid2.ui.account.AccountService; +import com.seafile.seadroid2.ui.file.FileService; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; @@ -45,10 +52,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.SocketTimeoutException; import java.nio.file.Files; import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.net.ssl.SSLHandshakeException; import okhttp3.Call; import okhttp3.MultipartBody; @@ -56,15 +71,95 @@ import okhttp3.RequestBody; import okhttp3.Response; -public abstract class BaseUploadFileWorker extends TransferWorker { +public abstract class BaseUploadWorker extends TransferWorker { + public abstract BaseTransferNotificationHelper getNotification(); - public BaseUploadFileWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + public BaseUploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); fileTransferProgressListener.setProgressListener(progressListener); } - public abstract BaseNotification getNotification(); + + private TransferResult parseTransferException(Exception e) { + if (e instanceof JSONException) { + return TransferResult.ENCODING_EXCEPTION; + } else if (e instanceof SeafException) { + if (e == SeafException.notFoundException) { + return TransferResult.FILE_NOT_FOUND; + } else if (e == SeafException.OUT_OF_QUOTA) { + return TransferResult.OUT_OF_QUOTA; + } else if (e == SeafException.networkException) { + return TransferResult.NETWORK_CONNECTION; + } else if (e == SeafException.sslException) { + return TransferResult.SSL_EXCEPTION; + } else if (e == SeafException.illFormatException) { + return TransferResult.ENCODING_EXCEPTION; + } else if (e == SeafException.notLoggedInException) { + return TransferResult.ACCOUNT_NOT_LOGGED_IN; + } else if (e == SeafException.notFoundUserException) { + return TransferResult.ACCOUNT_NOT_FOUND; + } + } else if (e instanceof UnsupportedEncodingException) { + return TransferResult.ENCODING_EXCEPTION; + } else if (e instanceof SSLHandshakeException) { + return TransferResult.SSL_EXCEPTION; + } else if (e instanceof SocketTimeoutException) { + return TransferResult.NETWORK_CONNECTION; + } else if (e instanceof IOException) { + return TransferResult.NETWORK_CONNECTION; + } + + return TransferResult.UNKNOWN; + } + + public TransferResult onException(FileTransferEntity transferEntity, Exception e) { + transferEntity.transfer_status = TransferStatus.FAILED; + transferEntity.action_end_at = System.currentTimeMillis(); + transferEntity.transfer_result = parseTransferException(e); + + //update db + AppDatabase.getInstance().fileTransferDAO().update(transferEntity); + + return transferEntity.transfer_result; + } + + + public void notifyError(TransferResult result) { + if (result == TransferResult.OUT_OF_QUOTA) { + getGeneralNotificationHelper().showErrorNotification(R.string.above_quota, getNotification().getDefaultTitle()); + } else if (result == TransferResult.NETWORK_CONNECTION) { + getGeneralNotificationHelper().showErrorNotification(R.string.network_error, getNotification().getDefaultTitle()); + } else if (result == TransferResult.ACCOUNT_NOT_FOUND) { + getGeneralNotificationHelper().showErrorNotification(R.string.saf_account_not_found_exception, getNotification().getDefaultTitle()); + } else { + getGeneralNotificationHelper().showErrorNotification(String.valueOf(result), getNotification().getDefaultTitle()); + } + } + + public String isInterrupt(TransferResult result) { + String finishFlagEvent = null; + if (result == TransferResult.ENCODING_EXCEPTION) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.FILE_NOT_FOUND) { +// finishFlagEvent = null; + } else if (result == TransferResult.OUT_OF_QUOTA) { + finishFlagEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; + } else if (result == TransferResult.NETWORK_CONNECTION) { + finishFlagEvent = TransferEvent.EVENT_CANCEL_WITH_NETWORK_ERR; + } else if (result == TransferResult.SSL_EXCEPTION) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.ACCOUNT_NOT_LOGGED_IN) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.ACCOUNT_NOT_FOUND) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } else if (result == TransferResult.UNKNOWN) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } + + return finishFlagEvent; + } + protected boolean calcQuota(List list) throws SeafException, IOException { @@ -107,23 +202,33 @@ protected AccountInfo getAccountInfo() throws IOException, SeafException { return accountInfo; } - /** * */ - protected void catchExceptionAndUpdateDB(FileTransferEntity transferEntity, Exception e) { + private final Set repoNetDataIsFetched = new HashSet<>(); - transferEntity.transfer_status = TransferStatus.FAILED; - transferEntity.action_end_at = System.currentTimeMillis(); + private ExistingFileStrategy compareLocal(File file, FileTransferEntity transferEntity) { + List entList = AppDatabase.getInstance().direntDao().getListByFullPathSync(transferEntity.repo_id, transferEntity.target_path); + if (CollectionUtils.isEmpty(entList)) { + return ExistingFileStrategy.NOT_FOUND_IN_REMOTE; + } - transferEntity.transfer_result = TransferUtils.convertException2TransferResult(e); - AppDatabase.getInstance().fileTransferDAO().update(transferEntity); + if (TextUtils.equals(transferEntity.file_id, entList.get(0).id)) { + return ExistingFileStrategy.SKIP; + } + + // improve + if (entList.get(0).size == file.length()) { + return ExistingFileStrategy.SKIP; + } + + return ExistingFileStrategy.APPEND; } /** * @return true: The file in repo already exists and does not need to be uploaded */ - protected ExistingFileStrategy checkRemoteFileExists(FileTransferEntity transferEntity) throws IOException, SeafException { + protected ExistingFileStrategy checkRemoteFileExists(Account account, RepoModel repoModel, FileTransferEntity transferEntity) throws IOException, SeafException { if (ExistingFileStrategy.REPLACE == transferEntity.file_strategy) { return ExistingFileStrategy.REPLACE; @@ -143,22 +248,62 @@ protected ExistingFileStrategy checkRemoteFileExists(FileTransferEntity transfer throw SeafException.notFoundException; } - DirentFileModel direntFileModel = getRemoteFile(repoId, remotePath); - if (direntFileModel == null) { - // nothing in remote - return ExistingFileStrategy.NOT_FOUND_IN_REMOTE; - } + List entList = AppDatabase.getInstance().direntDao().getListByFullPathSync(repoId, remotePath); + if (CollectionUtils.isEmpty(entList)) { + if (repoNetDataIsFetched.contains(repoId)) { + return ExistingFileStrategy.NOT_FOUND_IN_REMOTE; + } - if (TextUtils.equals(transferEntity.file_id, direntFileModel.id)) { - return ExistingFileStrategy.SKIP; - } + //load data from net + try { + boolean isSuccess = getRemoteDirentList(account, repoModel, transferEntity.getParent_path()); + if (isSuccess) { + repoNetDataIsFetched.add(repoId); - // improve - if (direntFileModel.size == file.length()) { - return ExistingFileStrategy.SKIP; + return compareLocal(file, transferEntity); + } + + } catch (SeafException e) { + + //Second attempt + DirentFileModel direntFileModel = getRemoteFile(repoId, remotePath); + if (direntFileModel == null) { + // nothing in remote + return ExistingFileStrategy.NOT_FOUND_IN_REMOTE; + } + + if (TextUtils.equals(transferEntity.file_id, direntFileModel.id)) { + return ExistingFileStrategy.SKIP; + } + + // improve + if (direntFileModel.size == file.length()) { + return ExistingFileStrategy.SKIP; + } + } + + return ExistingFileStrategy.APPEND; + } else { + return compareLocal(file, transferEntity); } - return ExistingFileStrategy.REPLACE; +// +// DirentFileModel direntFileModel = getRemoteFile(repoId, remotePath); +// if (direntFileModel == null) { +// // nothing in remote +// return ExistingFileStrategy.NOT_FOUND_IN_REMOTE; +// } +// +// if (TextUtils.equals(transferEntity.file_id, direntFileModel.id)) { +// return ExistingFileStrategy.SKIP; +// } +// +// // improve +// if (direntFileModel.size == file.length()) { +// return ExistingFileStrategy.SKIP; +// } + +// return ExistingFileStrategy.REPLACE; //FILE SYNC FEAT is not implemented in this version (v3.0.0). @@ -206,58 +351,32 @@ public void onProgressNotify(FileTransferEntity fileTransferEntity, int percent, // AppDatabase.getInstance().fileTransferDAO().update(fileTransferEntity); - sendProgress(fileTransferEntity.file_name, fileTransferEntity.uid, percent, transferredSize, totalSize, fileTransferEntity.data_source); + sendProgressNotifyEvent(fileTransferEntity.file_name, fileTransferEntity.uid, percent, transferredSize, totalSize, fileTransferEntity.data_source); } }; + private Call newCall; @Override public void onStopped() { super.onStopped(); - cancelNotification(); +// cancelNotification(); - if (newCall != null) { + if (newCall != null && !newCall.isCanceled()) { newCall.cancel(); } } - private void cancelNotification() { - if (getNotification() == null) { - return; - } - - BaseNotification notification = getNotification(); - if (notification instanceof AlbumBackupNotificationHelper) { - AlbumBackupNotificationHelper helper = (AlbumBackupNotificationHelper) notification; - helper.cancel(); - } else if (notification instanceof FolderBackupNotificationHelper) { - FolderBackupNotificationHelper helper = (FolderBackupNotificationHelper) notification; - helper.cancel(); - } else if (notification instanceof FileBackupNotificationHelper) { - FileBackupNotificationHelper helper = (FileBackupNotificationHelper) notification; - helper.cancel(); - } - } - private void notifyProgress(String fileName, int percent) { if (getNotification() == null) { return; } - BaseNotification notification = getNotification(); - if (notification instanceof AlbumBackupNotificationHelper) { - AlbumBackupNotificationHelper helper = (AlbumBackupNotificationHelper) notification; - helper.notifyProgress(fileName, percent); - } else if (notification instanceof FolderBackupNotificationHelper) { - FolderBackupNotificationHelper helper = (FolderBackupNotificationHelper) notification; - helper.notifyProgress(fileName, percent); - } else if (notification instanceof FileBackupNotificationHelper) { - FileBackupNotificationHelper helper = (FileBackupNotificationHelper) notification; - helper.notifyProgress(fileName, percent); - } - + BaseTransferNotificationHelper notification = getNotification(); + ForegroundInfo f = notification.getForegroundProgressNotification(fileName, percent); + showForegroundAsync(f); } public void transferFile(Account account, FileTransferEntity transferEntity) throws IOException, SeafException, JSONException { @@ -272,14 +391,18 @@ public void transferFile(Account account, FileTransferEntity transferEntity) thr return; } - if (repoModels.get(0).canLocalDecrypt()) { - uploadBlockFile(account, transferEntity); + RepoModel repo = repoModels.get(0); + if (repo.canLocalDecrypt()) { + uploadBlockFile(account, repo, transferEntity); } else { - uploadFile(account, transferEntity); + uploadFile(account, repo, transferEntity); } } - private void uploadFile(Account account, FileTransferEntity transferEntity) throws IOException, SeafException { + /** + * upload file + */ + private void uploadFile(Account account, RepoModel repoModel, FileTransferEntity transferEntity) throws IOException, SeafException { if (isStopped()) { return; } @@ -291,7 +414,7 @@ private void uploadFile(Account account, FileTransferEntity transferEntity) thro ExistingFileStrategy fileStrategy = transferEntity.file_strategy; if (fileStrategy == ExistingFileStrategy.AUTO) { - fileStrategy = checkRemoteFileExists(transferEntity); + fileStrategy = checkRemoteFileExists(account, repoModel, transferEntity); } if (fileStrategy == ExistingFileStrategy.SKIP) { @@ -343,41 +466,48 @@ private void uploadFile(Account account, FileTransferEntity transferEntity) thro throw SeafException.networkException; } - Request request = new Request.Builder() - .url(uploadUrl) - .post(requestBody) - .build(); - // - if (newCall != null && !newCall.isCanceled()) { - newCall.cancel(); + if (newCall != null && newCall.isExecuted()) { + SLogs.d("Folder upload: newCall has executed()"); } - newCall = IO.getInstanceWithLoggedIn().getClient().newCall(request); + try { - Response response = newCall.execute(); + Request request = new Request.Builder() + .url(uploadUrl) + .post(requestBody) + .build(); + newCall = IO.getInstanceWithLoggedIn().getClient().newCall(request); - if (!response.isSuccessful()) { - String b = response.body() != null ? response.body().string() : null; - SLogs.d("result,failed:" + b); + Response response = newCall.execute(); - //[text={"error": "Out of quota.\n"}] - if (b != null && b.toLowerCase().contains("out of quota")) { - throw SeafException.OUT_OF_QUOTA; - } + if (!response.isSuccessful()) { + String b = response.body() != null ? response.body().string() : null; + SLogs.d("result,failed:" + b); - throw SeafException.networkException; - } + // + newCall.cancel(); - String str = response.body().string(); - String fileId = str.replace("\"", ""); - SLogs.d("result,file ID:" + str); + //[text={"error": "Out of quota.\n"}] + if (b != null && b.toLowerCase().contains("out of quota")) { + throw SeafException.OUT_OF_QUOTA; + } - updateSuccess(transferEntity, fileId, file); + throw SeafException.networkException; + } + + String str = response.body().string(); + String fileId = str.replace("\"", ""); + SLogs.d("result,file ID:" + str); + + updateSuccess(transferEntity, fileId, file); + } catch (Exception e) { + throw e; + } } - private void uploadBlockFile(Account account, FileTransferEntity transferEntity) throws SeafException, IOException, JSONException { + private void uploadBlockFile(Account account, RepoModel repoModel, FileTransferEntity transferEntity) throws SeafException, IOException, JSONException { if (isStopped()) { return; } @@ -387,7 +517,7 @@ private void uploadBlockFile(Account account, FileTransferEntity transferEntity) throw SeafException.notFoundException; } - ExistingFileStrategy policy = checkRemoteFileExists(transferEntity); + ExistingFileStrategy policy = checkRemoteFileExists(account, repoModel, transferEntity); if (ExistingFileStrategy.SKIP == policy) { SLogs.d("skip block file(remote exists): " + transferEntity.target_path); @@ -447,6 +577,54 @@ private void uploadBlockFile(Account account, FileTransferEntity transferEntity) commitUpload(infoBean.commiturl, blkListId, transferEntity); } + private String getFileUploadUrl(String repoId, String target_dir, boolean isUpdate) throws IOException, SeafException { + retrofit2.Response res; + if (isUpdate) { + res = IO.getInstanceWithLoggedIn() + .execute(FileService.class) + .getFileUpdateLink(repoId) + .execute(); + } else { + +// target_dir = StringUtils.removeEnd(target_dir, "/"); + + res = IO.getInstanceWithLoggedIn() + .execute(FileService.class) + .getFileUploadLink(repoId, "/") + .execute(); + } + + if (!res.isSuccessful()) { + throw new SeafException(res.code(), res.message()); + } + + String urlStr = res.body(); + urlStr = StringUtils.replace(urlStr, "\"", ""); + + return urlStr; + } + + //block + private BlockInfoBean getFileBlockUploadUrl(Account account, String repoId, LinkedList blkListId) throws IOException, JSONException { + String ids = String.join(",", blkListId); + + Map requestDataMap = new HashMap<>(); + requestDataMap.put("blklist", ids); + + Map requestBodyMap = HttpUtils.generateRequestBody(requestDataMap); + + retrofit2.Response res = IO.getInstanceWithLoggedIn() + .execute(FileService.class) + .getFileBlockUploadLink(repoId, requestBodyMap) + .execute(); + + if (!res.isSuccessful()) { + return null; + } + + return res.body(); + } + /** * Upload file blocks to server @@ -494,8 +672,7 @@ private String uploadBlocksCommon(String link, List needUploadId, String /** * commit blocks to server */ - private void commitUpload(String link, List blkIds, FileTransferEntity transferEntity) - throws SeafException, IOException { + private void commitUpload(String link, List blkIds, FileTransferEntity transferEntity) throws SeafException, IOException { File file = new File(transferEntity.full_path); if (!file.exists()) { @@ -531,28 +708,31 @@ private void commitUpload(String link, List blkIds, FileTransferEntity t Request request = new Request.Builder().url(link).post(body).build(); // - if (newCall != null && !newCall.isCanceled()) { - newCall.cancel(); + if (newCall != null && newCall.isExecuted()) { + SLogs.d("Folder upload block: newCall has executed()"); } + try { + newCall = IO.getInstanceWithLoggedIn().getClient().newCall(request); + Response response = newCall.execute(); - newCall = IO.getInstanceWithLoggedIn().getClient().newCall(request); - Response response = newCall.execute(); + if (!response.isSuccessful()) { + String b = response.body() != null ? response.body().string() : null; + SLogs.d("上传结果,失败:" + b); - if (!response.isSuccessful()) { - String b = response.body() != null ? response.body().string() : null; - SLogs.d("上传结果,失败:" + b); + //[text={"error": "Out of quota.\n"}] + if (b != null && b.toLowerCase().contains("out of quota")) { + throw SeafException.OUT_OF_QUOTA; + } - //[text={"error": "Out of quota.\n"}] - if (b != null && b.toLowerCase().contains("out of quota")) { - throw SeafException.OUT_OF_QUOTA; + throw SeafException.networkException; } - throw SeafException.networkException; - } - - String fileId = response.body().string(); + String fileId = response.body().string(); - updateSuccess(transferEntity, fileId, file); + updateSuccess(transferEntity, fileId, file); + } catch (Exception e) { + throw e; + } } private void updateSuccess(FileTransferEntity transferEntity, String fileId, File file) { diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java new file mode 100644 index 000000000..e1870ad23 --- /dev/null +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/FolderBackupScannerWorker.java @@ -0,0 +1,339 @@ +package com.seafile.seadroid2.framework.worker.upload; + +import static com.seafile.seadroid2.config.Constants.PERIODIC_SCAN_INTERVALS; + +import android.content.Context; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.ForegroundInfo; +import androidx.work.WorkerParameters; + +import com.blankj.utilcode.util.CollectionUtils; +import com.seafile.seadroid2.R; +import com.seafile.seadroid2.account.Account; +import com.seafile.seadroid2.account.SupportAccountManager; +import com.seafile.seadroid2.config.Constants; +import com.seafile.seadroid2.framework.data.db.AppDatabase; +import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; +import com.seafile.seadroid2.framework.data.db.entities.RepoModel; +import com.seafile.seadroid2.framework.data.model.enums.TransferAction; +import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; +import com.seafile.seadroid2.framework.data.model.enums.TransferResult; +import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; +import com.seafile.seadroid2.framework.datastore.StorageManager; +import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; +import com.seafile.seadroid2.framework.notification.FolderBackupScanNotificationHelper; +import com.seafile.seadroid2.framework.util.SLogs; +import com.seafile.seadroid2.framework.util.Utils; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.ExistingFileStrategy; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; +import com.seafile.seadroid2.ui.folder_backup.RepoConfig; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + + +/** + *

+ * FileMonitor is {@link com.seafile.seadroid2.framework.file_monitor.SupportFileAlterationMonitor} + *

+ *

+ * Worker Tag: + * + * @see BackgroundJobManagerImpl#TAG_ALL + * @see BackgroundJobManagerImpl#TAG_TRANSFER + */ +public class FolderBackupScannerWorker extends TransferWorker { + public static final UUID UID = UUID.nameUUIDFromBytes(FolderBackupScannerWorker.class.getSimpleName().getBytes()); + + private final FolderBackupScanNotificationHelper notificationHelper; + + public FolderBackupScannerWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + + notificationHelper = new FolderBackupScanNotificationHelper(context); + } + + @NonNull + @Override + public Result doWork() { + Account account = SupportAccountManager.getInstance().getCurrentAccount(); + if (account == null) { + return Result.success(); + } + + String[] ids = getInputData().getStringArray(TransferWorker.DATA_CANCEL_IDS); + if (ids != null && ids.length > 0) { + List idList = Arrays.asList(ids); + // + removeFromDB(idList); + + BackgroundJobManagerImpl.getInstance().startFolderUploadWorker(); + + return Result.success(); + } + + boolean canScan = checkCanScan(); + if (!canScan) { + SLogs.i("The folder scan task was not started"); + + BackgroundJobManagerImpl.getInstance().startFolderUploadWorker(); + + return Result.success(getScanEndData()); + } + + List backupPaths = FolderBackupManager.readBackupPaths(); + RepoConfig repoConfig = FolderBackupManager.readRepoConfig(); + if (CollectionUtils.isEmpty(backupPaths) || repoConfig == null) { + + return Result.success(getScanEndData()); + } + + // + String title = getApplicationContext().getString(R.string.settings_folder_backup_info_title); + String subTitle = getApplicationContext().getString(R.string.is_scanning); + + ForegroundInfo foregroundInfo = notificationHelper.getForegroundNotification(title, subTitle); + showForegroundAsync(foregroundInfo); +// notificationHelper.showNotification(nTitle); + + try { + //send a scan event + sendEvent(TransferEvent.EVENT_SCANNING, TransferDataSource.FOLDER_BACKUP); + + //do + traverseBackupPath(account, repoConfig, backupPaths); + + } finally { + // +// notificationHelper.cancel(); + + FolderBackupManager.writeLastScanTime(System.currentTimeMillis()); + + //start upload worker + BackgroundJobManagerImpl.getInstance().startFolderUploadWorker(); + } + + return Result.success(getScanEndData()); + } + + private Data getScanEndData() { + return new Data.Builder() + .putString(TransferWorker.KEY_DATA_EVENT, TransferEvent.EVENT_SCAN_END) + .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.FOLDER_BACKUP)) + .build(); + } + + private boolean checkCanScan() { + boolean isOpenBackup = FolderBackupManager.readBackupSwitch(); + if (!isOpenBackup) { + return false; + } + + boolean isForce = getInputData().getBoolean(TransferWorker.DATA_FORCE_TRANSFER_KEY, false); + if (isForce) { + return true; + } + + long lastScanTime = FolderBackupManager.readLastScanTime(); + if (lastScanTime != 0) { + long now = System.currentTimeMillis(); + if (now - lastScanTime < PERIODIC_SCAN_INTERVALS) { + return false; + } + } + + return true; + } + + private void removeFromDB(List ids) { + List dbList = AppDatabase.getInstance().fileTransferDAO().getListByUidsSync(ids); + if (CollectionUtils.isEmpty(dbList)) { + return; + } + + for (FileTransferEntity fileTransferEntity : dbList) { + AppDatabase.getInstance().fileTransferDAO().deleteOne(fileTransferEntity); + } + } + + private void traverseBackupPath(Account account, RepoConfig repoConfig, List backupPathsList) { + + List repoModels = AppDatabase.getInstance().repoDao().getByIdSync(repoConfig.getRepoID()); + + if (CollectionUtils.isEmpty(repoModels)) { + return; + } + + RepoModel repoModel = repoModels.get(0); + + for (String backupPath : backupPathsList) { + long lastTime = FolderBackupManager.readBackupPathLastScanTime(backupPath); + + //iterate over local files + List localFiles = traverseFiles(backupPath, lastTime); + + //write last scan time + FolderBackupManager.writeBackupPathLastScanTime(backupPath); + + if (CollectionUtils.isEmpty(localFiles)) { + SLogs.e("没有新增、更新的文件: " + backupPath); + continue; + } + SLogs.e("新文件: " + localFiles.size()); + + int pageSize = 99; + if (localFiles.size() < pageSize) { + pageSize = localFiles.size(); + } + + for (int pageNumber = 1; pageNumber <= (localFiles.size() + pageSize - 1) / pageSize; pageNumber++) { + int fromIndex = (pageNumber - 1) * pageSize; + int toIndex = Math.min(pageNumber * pageSize, localFiles.size()); + List subFiles = localFiles.subList(fromIndex, toIndex); + + compareToLocalAndInsert(account, repoModel, backupPath, subFiles); + } + } + } + + private void compareToLocalAndInsert(Account account, RepoModel repoModel, String backupPath, List subFiles) { + if (CollectionUtils.isEmpty(subFiles)) { + return; + } + + List fullPaths = subFiles.stream().map(File::getAbsolutePath).collect(Collectors.toList()); + + List tempExistsList = AppDatabase + .getInstance() + .fileTransferDAO() + .getListByFullPathsSync(repoModel.repo_id, fullPaths, TransferAction.UPLOAD); + + List tList = CollectionUtils.newArrayList(); + for (File file : subFiles) { + FileTransferEntity fEntity = FileTransferEntity.convert2ThisForUploadFileSyncWorker(account, repoModel, file, backupPath); + if (fEntity != null) { + tList.add(fEntity); + } + } + + if (CollectionUtils.isEmpty(tempExistsList)) { + AppDatabase.getInstance().fileTransferDAO().insertAll(tList); + return; + } + + List newList = CollectionUtils.newArrayList(); + + int i = 0; + + for (FileTransferEntity transferEntity : tList) { + i++; + + Optional optional = tempExistsList.stream().filter(f -> TextUtils.equals(f.full_path, transferEntity.full_path)).findFirst(); + if (!optional.isPresent()) { + newList.add(transferEntity); + SLogs.d(i + " :folder backup scan: new file(local empty): " + transferEntity.target_path); + continue; + } + + FileTransferEntity dbEntity = optional.get(); + if (dbEntity.data_status == Constants.DataStatus.DELETED) { + // has been deleted in db. + SLogs.d(i + " :folder backup scan: skip file(deleted): " + transferEntity.target_path); + + } else if (TextUtils.equals(dbEntity.file_md5, transferEntity.file_md5)) { + //it's the same file,do not insert into db. + SLogs.d(i + " :folder backup scan: skip file(same file): " + transferEntity.target_path); + + } else { + SLogs.d(i + " :folder backup scan: new file: " + transferEntity.target_path); + + transferEntity.transfer_action = TransferAction.UPLOAD; + transferEntity.transfer_result = TransferResult.NO_RESULT; + transferEntity.transfer_status = TransferStatus.WAITING; + transferEntity.file_strategy = ExistingFileStrategy.REPLACE; + newList.add(transferEntity); + } + } + + if (CollectionUtils.isEmpty(newList)) { + AppDatabase.getInstance().fileTransferDAO().insertAll(newList); + } + + } + + + private List traverseFiles(String path, long lastScanTime) { + Deque stack = new ArrayDeque<>(); + stack.push(new File(path)); + + //skip folder: /storage/emulated/0/Android/media/com.seafile.seadroid2.debug/ + String lPath = StorageManager.getInstance().getMediaDir().getAbsolutePath(); + lPath = Utils.getParentPath(lPath); + + List filePathList = new ArrayList<>(); + + boolean isSkipHiddenFile = FolderBackupManager.isFolderBackupSkipHiddenFiles(); + + while (!stack.isEmpty()) { + File currentDir = stack.pop(); + File[] files = currentDir.listFiles(); + + if (files == null) { + continue; + } + + for (File file : files) { + if (isSkipHiddenFile && file.isHidden()) { + continue; + } + + if (file.isDirectory()) { + stack.push(file); + } else { + processFile(file, filePathList, lPath, lastScanTime); + } + } + } + + return filePathList; + } + + private void processFile(File file, List filePathList, String lPath, long lastScanTime) { + String fPath = file.getAbsolutePath(); + + if (fPath.startsWith(lPath)) { + return; + } + + if (lastScanTime > 0) { + try { + BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class); + long created = attr.creationTime().toMillis(); + long modified = attr.lastModifiedTime().toMillis(); + + if (created > lastScanTime || modified > lastScanTime) { + filePathList.add(file); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } else { + filePathList.add(file); + } + } +} diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/MediaBackupScannerWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java similarity index 89% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/MediaBackupScannerWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java index 3b4b8ef03..985479ba2 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/MediaBackupScannerWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/MediaBackupScannerWorker.java @@ -1,4 +1,4 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.upload; import static com.seafile.seadroid2.config.Constants.PERIODIC_SCAN_INTERVALS; @@ -10,9 +10,12 @@ import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.ForegroundInfo; import androidx.work.WorkerParameters; import com.blankj.utilcode.util.CollectionUtils; +import com.blankj.utilcode.util.FileUtils; import com.google.common.base.Joiner; import com.seafile.seadroid2.R; import com.seafile.seadroid2.SeadroidApplication; @@ -20,6 +23,7 @@ import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.account.SupportAccountManager; import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; +import com.seafile.seadroid2.framework.datastore.DataManager; import com.seafile.seadroid2.framework.datastore.StorageManager; import com.seafile.seadroid2.framework.data.db.AppDatabase; import com.seafile.seadroid2.framework.data.db.entities.DirentModel; @@ -28,8 +32,12 @@ import com.seafile.seadroid2.framework.data.model.repo.DirentWrapperModel; import com.seafile.seadroid2.framework.datastore.sp.AlbumBackupManager; import com.seafile.seadroid2.framework.http.IO; +import com.seafile.seadroid2.framework.notification.AlbumBackupScanNotificationHelper; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.notification.AlbumBackupNotificationHelper; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import com.seafile.seadroid2.ui.file.FileService; import com.seafile.seadroid2.ui.folder_backup.RepoConfig; import com.seafile.seadroid2.ui.repo.RepoService; @@ -61,7 +69,7 @@ public class MediaBackupScannerWorker extends TransferWorker { public static final UUID UID = UUID.nameUUIDFromBytes(MediaBackupScannerWorker.class.getSimpleName().getBytes()); - private AlbumBackupNotificationHelper albumNotificationHelper; + private final AlbumBackupScanNotificationHelper albumNotificationHelper; private final String BASE_DIR = "My Photos"; @@ -73,7 +81,7 @@ public class MediaBackupScannerWorker extends TransferWorker { public MediaBackupScannerWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); - albumNotificationHelper = new AlbumBackupNotificationHelper(context); + albumNotificationHelper = new AlbumBackupScanNotificationHelper(context); account = SupportAccountManager.getInstance().getCurrentAccount(); } @@ -86,43 +94,41 @@ public Result doWork() { return Result.success(); } - boolean canScan = checkCanScan(); if (!canScan) { SLogs.d("UploadMediaScanWorker: do not start the media scan task this time"); - //start media backup worker BackgroundJobManagerImpl.getInstance().startMediaBackupWorker(); - return Result.success(); - } - // + //start media backup worker + return Result.success(getScanEndData()); + } - String nTitle = getApplicationContext().getString(R.string.settings_camera_upload_info_title); - nTitle += " - " + getApplicationContext().getString(R.string.is_scanning); + //todo + String title = getApplicationContext().getString(R.string.settings_camera_upload_info_title); + String subTitle = getApplicationContext().getString(R.string.is_scanning); - albumNotificationHelper.showNotification(nTitle); - albumNotificationHelper.cancel(3000); + ForegroundInfo foregroundInfo = albumNotificationHelper.getForegroundNotification(title, subTitle); + showForegroundAsync(foregroundInfo); SLogs.d("MediaSyncWorker start"); try { - sendProgressEvent(TransferEvent.EVENT_SCANNING); + sendEvent(TransferEvent.EVENT_SCANNING, TransferDataSource.ALBUM_BACKUP); loadMedia(); + } catch (SeafException | IOException e) { SLogs.e("MediaBackupScannerWorker has occurred error", e); } finally { // AlbumBackupManager.writeLastScanTime(System.currentTimeMillis()); - sendProgressEvent(TransferEvent.EVENT_SCAN_END); - //start upload worker BackgroundJobManagerImpl.getInstance().startMediaBackupWorker(); } - return Result.success(); + return Result.success(getScanEndData()); } private boolean checkCanScan() { @@ -132,7 +138,7 @@ private boolean checkCanScan() { } boolean isForce = getInputData().getBoolean(TransferWorker.DATA_FORCE_TRANSFER_KEY, false); - if (isForce){ + if (isForce) { return true; } @@ -147,6 +153,13 @@ private boolean checkCanScan() { return true; } + private Data getScanEndData() { + return new Data.Builder() + .putString(TransferWorker.KEY_DATA_EVENT, TransferEvent.EVENT_SCAN_END) + .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.ALBUM_BACKUP)) + .build(); + } + private void loadMedia() throws SeafException, IOException { repoConfig = AlbumBackupManager.readRepoConfig(); @@ -154,7 +167,8 @@ private void loadMedia() throws SeafException, IOException { if (repoConfig == null) { SLogs.d("MediaSyncWorker: repoConfig is null"); - sendProgressEvent(TransferEvent.EVENT_TRANSFERRED_WITH_DATA); + + sendEvent(TransferEvent.EVENT_FINISH, TransferDataSource.ALBUM_BACKUP); return; } @@ -307,6 +321,13 @@ private String varArgs(int count) { */ private void iterateCursor(Cursor cursor, String media) { +// String repoId = repoConfig.getRepoID(); +// String repoName = repoConfig.getRepoName(); +// File localRepoFilePath = DataManager.getLocalRepoPath(account, repoId, repoName); +// String localRepoPhotoPath = Utils.pathJoin(localRepoFilePath.getAbsolutePath(), BASE_DIR); + + String localCacheAbsPath = StorageManager.getInstance().getMediaDir().getAbsolutePath(); + // upload them one by one while (!isStopped() && cursor.moveToNext()) { @@ -348,7 +369,6 @@ private void iterateCursor(Cursor cursor, String media) { int dateAddIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED); dateAdded = cursor.getLong(dateAddIndex); - file = new File(cursor.getString(dataColumn)); } @@ -361,8 +381,10 @@ private void iterateCursor(Cursor cursor, String media) { continue; } + +// boolean isCached = FileUtils.isFileExists(Utils.pathJoin(localRepoPhotoPath,file.getName())); // Ignore all media by Seafile. We don't want to upload our own cached files. - if (file.getAbsolutePath().startsWith(StorageManager.getInstance().getMediaDir().getAbsolutePath())) { + if (file.getAbsolutePath().startsWith(localCacheAbsPath)) { SLogs.d("skip file -> " + file.getAbsolutePath() + ", because it's part of the Seadroid cache"); continue; } @@ -419,6 +441,7 @@ private void forceCreateDirectory(String parent, String dirIsBucketName, List / + //todo 使用获取 path 详情接口 //get parent dirent list Call direntWrapperModelCall = IO.getInstanceWithLoggedIn().execute(RepoService.class).getDirentsSync(repoConfig.getRepoID(), parent); retrofit2.Response res = direntWrapperModelCall.execute(); diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadFileManuallyWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java similarity index 57% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/UploadFileManuallyWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java index 54f6eec0f..6766df87e 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadFileManuallyWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFileManuallyWorker.java @@ -1,10 +1,12 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.upload; import android.content.Context; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.work.Data; +import androidx.work.ForegroundInfo; +import androidx.work.ListenableWorker; import androidx.work.WorkerParameters; import com.blankj.utilcode.util.CollectionUtils; @@ -21,7 +23,11 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferResult; import com.seafile.seadroid2.framework.notification.FileBackupNotificationHelper; import com.seafile.seadroid2.framework.notification.base.BaseNotification; +import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; import com.seafile.seadroid2.framework.util.SLogs; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import java.util.List; import java.util.UUID; @@ -33,7 +39,7 @@ * @see BackgroundJobManagerImpl#TAG_ALL * @see BackgroundJobManagerImpl#TAG_TRANSFER */ -public class UploadFileManuallyWorker extends BaseUploadFileWorker { +public class UploadFileManuallyWorker extends BaseUploadWorker { public static final UUID UID = UUID.nameUUIDFromBytes(UploadFileManuallyWorker.class.getSimpleName().getBytes()); private final FileBackupNotificationHelper notificationManager; @@ -45,50 +51,55 @@ public UploadFileManuallyWorker(@NonNull Context context, @NonNull WorkerParamet } @Override - public BaseNotification getNotification() { + public BaseTransferNotificationHelper getNotification() { return notificationManager; } @NonNull @Override - public Result doWork() { + public ListenableWorker.Result doWork() { return start(); } /** * The task here may not be from the current account */ - private Result start() { + private ListenableWorker.Result start() { - notificationManager.cancel(); - notificationManager.showNotification(); + ForegroundInfo foregroundInfo = notificationManager.getForegroundNotification(); + showForegroundAsync(foregroundInfo); + +// notificationManager.cancel(); +// notificationManager.showNotification(); boolean isUploaded = false; - String outEvent = null; + String finishFlagEvent = null; while (true) { SLogs.d("start upload file worker"); if (isStopped()) { - return Result.success(); + return ListenableWorker.Result.success(); } - List transferList = AppDatabase.getInstance().fileTransferDAO() + List transferList = AppDatabase + .getInstance().fileTransferDAO() .getOnePendingTransferAllAccountSync( TransferAction.UPLOAD, - TransferDataSource.FILE_BACKUP); + TransferDataSource.FILE_BACKUP + ); if (CollectionUtils.isEmpty(transferList)) { break; } - FileTransferEntity transfer = transferList.get(0); + FileTransferEntity transferEntity = transferList.get(0); try { - boolean isAmple = calcQuota(CollectionUtils.newArrayList(transfer)); + boolean isAmple = calcQuota(CollectionUtils.newArrayList(transferEntity)); if (!isAmple) { getGeneralNotificationHelper().showErrorNotification(R.string.above_quota, R.string.settings_folder_backup_info_title); AppDatabase.getInstance().fileTransferDAO().cancelWithFileBackup(TransferResult.OUT_OF_QUOTA); - outEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; + finishFlagEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; break; } } catch (Exception e) { @@ -97,9 +108,10 @@ private Result start() { } isUploaded = true; + try { - String relatedAccount = transfer.related_account; + String relatedAccount = transferEntity.related_account; Account account = SupportAccountManager.getInstance().getSpecialAccount(relatedAccount); if (account == null) { SLogs.d("account is null : " + relatedAccount); @@ -109,39 +121,57 @@ private Result start() { throw SeafException.notLoggedInException; } - transferFile(account, transfer); + transferFile(account, transferEntity); + sendTransferEvent(transferEntity, true); } catch (Exception e) { - SLogs.e(e); - catchExceptionAndUpdateDB(transfer, e); + SLogs.e("upload file file failed: ", e); + isUploaded = false; + + TransferResult transferResult = onException(transferEntity, e); + + notifyError(transferResult); + + sendTransferEvent(transferEntity, false); + + String finishFlag = isInterrupt(transferResult); + if (!TextUtils.isEmpty(finishFlag)) { + finishFlagEvent = finishFlag; + break; + } + } finally { // After the user selects the file and completes the upload, // the APP will no longer cache the file in ".../android/Media/Seafile/..." - FileUtils.delete(transfer.full_path); + FileUtils.delete(transferEntity.full_path); } } - if (isUploaded) { ToastUtils.showLong(R.string.upload_finished); - SLogs.d("UploadFileManuallyWorker all task run"); - if (outEvent == null) { - outEvent = TransferEvent.EVENT_TRANSFERRED_WITH_DATA; - } - } else { - SLogs.d("UploadFileManuallyWorker nothing to run"); - if (outEvent == null) { - outEvent = TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA; - } } - notificationManager.cancel(); + SLogs.e("UploadFileManuallyWorker all task run"); + + if (finishFlagEvent == null) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } + +// Account account = SupportAccountManager.getInstance().getCurrentAccount(); +// int pendingCount = AppDatabase +// .getInstance() +// .fileTransferDAO() +// .countPendingTransferSync(account.getSignature(), +// TransferAction.UPLOAD, +// TransferDataSource.FILE_BACKUP +// ); - //Send a completion event Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, outEvent) + .putString(TransferWorker.KEY_DATA_EVENT, finishFlagEvent) +// .putInt(TransferWorker.KEY_DATA_PARAM, pendingCount) .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.FILE_BACKUP)) .build(); - return Result.success(data); + return ListenableWorker.Result.success(data); } + } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadFolderFileAutomaticallyWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java similarity index 54% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/UploadFolderFileAutomaticallyWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java index dd735469f..ff8693d33 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadFolderFileAutomaticallyWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadFolderFileAutomaticallyWorker.java @@ -1,10 +1,12 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.upload; import android.content.Context; import android.os.Build; +import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.work.Data; +import androidx.work.ForegroundInfo; import androidx.work.WorkInfo; import androidx.work.WorkerParameters; @@ -20,8 +22,12 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferResult; import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; import com.seafile.seadroid2.framework.notification.base.BaseNotification; +import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.notification.FolderBackupNotificationHelper; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import java.util.List; import java.util.UUID; @@ -33,7 +39,7 @@ * @see BackgroundJobManagerImpl#TAG_ALL * @see BackgroundJobManagerImpl#TAG_TRANSFER */ -public class UploadFolderFileAutomaticallyWorker extends BaseUploadFileWorker { +public class UploadFolderFileAutomaticallyWorker extends BaseUploadWorker { public static final UUID UID = UUID.nameUUIDFromBytes(UploadFolderFileAutomaticallyWorker.class.getSimpleName().getBytes()); private final FolderBackupNotificationHelper notificationManager; @@ -45,7 +51,7 @@ public UploadFolderFileAutomaticallyWorker(@NonNull Context context, @NonNull Wo } @Override - public BaseNotification getNotification() { + public BaseTransferNotificationHelper getNotification() { return notificationManager; } @@ -55,8 +61,17 @@ public Result doWork() { return start(); } + @Override + public void onStopped() { + super.onStopped(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + SLogs.e("文件夹备份已停止:" + getStopReason()); + } + } + private Result start() { - notificationManager.cancel(); +// notificationManager.cancel(); Account account = SupportAccountManager.getInstance().getCurrentAccount(); if (account == null) { @@ -70,87 +85,90 @@ private Result start() { boolean isUploaded = false; - notificationManager.showNotification(); - String outEvent = null; + ForegroundInfo foregroundInfo = notificationManager.getForegroundNotification(); + showForegroundAsync(foregroundInfo); + +// notificationManager.showNotification(); + + String finishFlagEvent = null; + + SLogs.d("start upload file worker"); + sendEvent(TransferEvent.EVENT_TRANSFERRING, TransferDataSource.FILE_BACKUP); while (true) { if (isStopped()) { - return Result.success(); + break; } - SLogs.d("start upload file worker"); - //check - List transferList = AppDatabase.getInstance().fileTransferDAO() - .getOnePendingTransferSync(account.getSignature(), - TransferAction.UPLOAD, TransferDataSource.FOLDER_BACKUP); + List transferList = AppDatabase.getInstance() + .fileTransferDAO() + .getOnePendingTransferSync( + account.getSignature(), + TransferAction.UPLOAD, + TransferDataSource.FOLDER_BACKUP + ); if (CollectionUtils.isEmpty(transferList)) { break; } - FileTransferEntity transfer = transferList.get(0); + FileTransferEntity transferEntity = transferList.get(0); + isUploaded = true; try { - boolean isAmple = calcQuota(CollectionUtils.newArrayList(transfer)); - if (!isAmple) { - getGeneralNotificationHelper().showErrorNotification(R.string.above_quota, R.string.settings_folder_backup_info_title); - // - AppDatabase.getInstance().fileTransferDAO().cancel(account.getSignature(), TransferDataSource.FOLDER_BACKUP, TransferResult.OUT_OF_QUOTA); + transferFile(account, transferEntity); - outEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; - - break; - } + sendTransferEvent(transferEntity, true); } catch (Exception e) { - e.printStackTrace(); - break; - } - - isUploaded = true; + isUploaded = false; + SLogs.e("upload folder file failed: ", e); - try { + TransferResult transferResult = onException(transferEntity, e); - transferFile(account, transfer); + notifyError(transferResult); - } catch (Exception e) { - SLogs.e(e); - catchExceptionAndUpdateDB(transfer, e); + sendTransferEvent(transferEntity, false); - ToastUtils.showLong(R.string.upload_failed); - isUploaded = false; + String finishFlag = isInterrupt(transferResult); + if (!TextUtils.isEmpty(finishFlag)) { + finishFlagEvent = finishFlag; + break; + } } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - if (getStopReason() == WorkInfo.STOP_REASON_CANCELLED_BY_APP) { + if (getStopReason() >= WorkInfo.STOP_REASON_CANCELLED_BY_APP) { isUploaded = false; } } if (isUploaded) { ToastUtils.showLong(R.string.upload_finished); - SLogs.d("UploadFolderFileAutomaticallyWorker all task run"); - if (outEvent == null) { - outEvent = TransferEvent.EVENT_TRANSFERRED_WITH_DATA; - } - } else { - SLogs.d("UploadFolderFileAutomaticallyWorker nothing to run"); - if (outEvent == null) { - outEvent = TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA; - } } - notificationManager.cancel(); + SLogs.e("UploadFolderFileAutomaticallyWorker all task run"); + + if (finishFlagEvent == null) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } + +// int pendingCount = AppDatabase +// .getInstance() +// .fileTransferDAO() +// .countPendingTransferSync(account.getSignature(), +// TransferAction.UPLOAD, +// TransferDataSource.FOLDER_BACKUP +// ); - //Send a completion event Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, outEvent) + .putString(TransferWorker.KEY_DATA_EVENT, finishFlagEvent) +// .putInt(TransferWorker.KEY_DATA_PARAM, pendingCount) .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.FOLDER_BACKUP)) .build(); return Result.success(data); } - } diff --git a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadMediaFileAutomaticallyWorker.java b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java similarity index 55% rename from app/src/main/java/com/seafile/seadroid2/framework/worker/UploadMediaFileAutomaticallyWorker.java rename to app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java index ebc28efcf..831585a0e 100644 --- a/app/src/main/java/com/seafile/seadroid2/framework/worker/UploadMediaFileAutomaticallyWorker.java +++ b/app/src/main/java/com/seafile/seadroid2/framework/worker/upload/UploadMediaFileAutomaticallyWorker.java @@ -1,10 +1,13 @@ -package com.seafile.seadroid2.framework.worker; +package com.seafile.seadroid2.framework.worker.upload; import android.content.Context; import android.os.Build; +import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.work.Data; +import androidx.work.ForegroundInfo; +import androidx.work.ListenableWorker; import androidx.work.WorkInfo; import androidx.work.WorkerParameters; @@ -20,8 +23,12 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferResult; import com.seafile.seadroid2.framework.datastore.sp.AlbumBackupManager; import com.seafile.seadroid2.framework.notification.base.BaseNotification; +import com.seafile.seadroid2.framework.notification.base.BaseTransferNotificationHelper; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.notification.AlbumBackupNotificationHelper; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import java.util.List; import java.util.UUID; @@ -32,7 +39,7 @@ * @see BackgroundJobManagerImpl#TAG_ALL * @see BackgroundJobManagerImpl#TAG_TRANSFER */ -public class UploadMediaFileAutomaticallyWorker extends BaseUploadFileWorker { +public class UploadMediaFileAutomaticallyWorker extends BaseUploadWorker { public static final UUID UID = UUID.nameUUIDFromBytes(UploadMediaFileAutomaticallyWorker.class.getSimpleName().getBytes()); private final AlbumBackupNotificationHelper albumNotificationHelper; @@ -44,28 +51,36 @@ public UploadMediaFileAutomaticallyWorker(@NonNull Context context, @NonNull Wor } @Override - public BaseNotification getNotification() { + public BaseTransferNotificationHelper getNotification() { return albumNotificationHelper; } @NonNull @Override - public Result doWork() { - - albumNotificationHelper.cancel(); + public ListenableWorker.Result doWork() { Account account = SupportAccountManager.getInstance().getCurrentAccount(); if (account == null) { - return Result.failure(); + + notifyError(TransferResult.ACCOUNT_NOT_FOUND); + + return ListenableWorker.Result.success(); } boolean isEnable = AlbumBackupManager.readBackupSwitch(); if (!isEnable) { - return Result.success(); + return ListenableWorker.Result.success(); } - String outEvent = null; + //send start transfer event + sendEvent(TransferEvent.EVENT_TRANSFERRING, TransferDataSource.ALBUM_BACKUP); + // show foreground notification + ForegroundInfo foregroundInfo = albumNotificationHelper.getForegroundNotification(); + showForegroundAsync(foregroundInfo); + + // + String finishFlagEvent = null; boolean isUploaded = false; while (true) { if (isStopped()) { @@ -74,46 +89,45 @@ public Result doWork() { SLogs.d("start upload media worker"); - List transferList = AppDatabase.getInstance().fileTransferDAO() + List transferList = AppDatabase + .getInstance() + .fileTransferDAO() .getOnePendingTransferSync(account.getSignature(), TransferAction.UPLOAD, - TransferDataSource.ALBUM_BACKUP); + TransferDataSource.ALBUM_BACKUP + ); if (CollectionUtils.isEmpty(transferList)) { break; } - FileTransferEntity transfer = transferList.get(0); - - try { - boolean isAmple = calcQuota(CollectionUtils.newArrayList(transfer)); - if (!isAmple) { - getGeneralNotificationHelper().showErrorNotification(R.string.above_quota, R.string.settings_camera_upload_info_title); - AppDatabase.getInstance().fileTransferDAO().cancel(account.getSignature(), TransferDataSource.ALBUM_BACKUP, TransferResult.OUT_OF_QUOTA); - - outEvent = TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA; - break; - } - } catch (Exception e) { - e.printStackTrace(); - break; - } + FileTransferEntity transferEntity = transferList.get(0); isUploaded = true; try { - transferFile(account, transfer); + transferFile(account, transferEntity); + sendTransferEvent(transferEntity, true); } catch (Exception e) { SLogs.e("upload media file failed: ", e); - catchExceptionAndUpdateDB(transfer, e); - - ToastUtils.showLong(R.string.upload_failed); isUploaded = false; + + TransferResult transferResult = onException(transferEntity, e); + + notifyError(transferResult); + + sendTransferEvent(transferEntity, false); + + String finishFlag = isInterrupt(transferResult); + if (!TextUtils.isEmpty(finishFlag)) { + finishFlagEvent = finishFlag; + break; + } } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - if (getStopReason() == WorkInfo.STOP_REASON_CANCELLED_BY_APP) { + if (getStopReason() >= WorkInfo.STOP_REASON_CANCELLED_BY_APP) { isUploaded = false; } } @@ -121,22 +135,24 @@ public Result doWork() { // if (isUploaded) { ToastUtils.showLong(R.string.upload_finished); - SLogs.d("UploadMediaFileAutomaticallyWorker all task run"); - if (outEvent == null) { - outEvent = TransferEvent.EVENT_TRANSFERRED_WITH_DATA; - } - } else { - if (outEvent == null) { - outEvent = TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA; - } - SLogs.d("UploadMediaFileAutomaticallyWorker nothing to run"); } - albumNotificationHelper.cancel(); + SLogs.e("UploadMediaFileAutomaticallyWorker all task run"); + if (finishFlagEvent == null) { + finishFlagEvent = TransferEvent.EVENT_FINISH; + } + +// int pendingCount = AppDatabase +// .getInstance() +// .fileTransferDAO() +// .countPendingTransferSync(account.getSignature(), +// TransferAction.UPLOAD, +// TransferDataSource.ALBUM_BACKUP +// ); - //Send a completion event Data data = new Data.Builder() - .putString(TransferWorker.KEY_DATA_EVENT, outEvent) + .putString(TransferWorker.KEY_DATA_EVENT, finishFlagEvent) +// .putInt(TransferWorker.KEY_DATA_PARAM, pendingCount) .putString(TransferWorker.KEY_DATA_TYPE, String.valueOf(TransferDataSource.ALBUM_BACKUP)) .build(); return Result.success(data); diff --git a/app/src/main/java/com/seafile/seadroid2/ssl/SSLSeafileSocketFactory.java b/app/src/main/java/com/seafile/seadroid2/ssl/SSLSeafileSocketFactory.java index 8f940e03c..ef88d9e12 100644 --- a/app/src/main/java/com/seafile/seadroid2/ssl/SSLSeafileSocketFactory.java +++ b/app/src/main/java/com/seafile/seadroid2/ssl/SSLSeafileSocketFactory.java @@ -26,6 +26,7 @@ * based on: * https://stackoverflow.com/questions/1037590/which-cipher-suites-to-enable-for-ssl-socket */ +@Deprecated public class SSLSeafileSocketFactory extends SSLSocketFactory { private SSLContext context; diff --git a/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java b/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java index 69e7d164e..29ea2dbf5 100644 --- a/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java +++ b/app/src/main/java/com/seafile/seadroid2/ssl/SSLTrustManager.java @@ -29,7 +29,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; - +@Deprecated public final class SSLTrustManager { public enum SslFailureReason { CERT_NOT_TRUSTED, diff --git a/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java index 71c351f31..9c6d314f3 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/activities/AllActivitiesFragment.java @@ -88,19 +88,13 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) { } - private boolean isFirstLoadData = true; - @Override - public void onResume() { - super.onResume(); - d("load data:onResume"); - if (isFirstLoadData) { - isFirstLoadData = false; - d("load data:isFirstLoadData"); - loadNext(); - } + public void onFirstResume() { + super.onFirstResume(); + loadNext(); } + private void initAdapter() { adapter = new ActivityAdapter(); TextView tipView = TipsViews.getTipTextView(requireContext()); @@ -115,6 +109,16 @@ private void initAdapter() { checkOpen(activityModel); }); + LogicLoadMoreAdapter loadMoreAdapter = getLogicLoadMoreAdapter(); + + helper = new QuickAdapterHelper.Builder(adapter) + .setTrailingLoadStateAdapter(loadMoreAdapter) + .build(); + binding.rv.setAdapter(helper.getAdapter()); + } + + @NonNull + private LogicLoadMoreAdapter getLogicLoadMoreAdapter() { LogicLoadMoreAdapter loadMoreAdapter = new LogicLoadMoreAdapter(); loadMoreAdapter.setOnLoadMoreListener(new TrailingLoadStateAdapter.OnTrailingListener() { @Override @@ -133,11 +137,7 @@ public boolean isAllowLoading() { return !binding.swipeRefreshLayout.isRefreshing(); } }); - - helper = new QuickAdapterHelper.Builder(adapter) - .setTrailingLoadStateAdapter(loadMoreAdapter) - .build(); - binding.rv.setAdapter(helper.getAdapter()); + return loadMoreAdapter; } private void showErrorTip() { diff --git a/app/src/main/java/com/seafile/seadroid2/ui/base/fragment/BaseFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/base/fragment/BaseFragment.java index 2c1e12097..fc1de61a4 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/base/fragment/BaseFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/base/fragment/BaseFragment.java @@ -8,4 +8,25 @@ public class BaseFragment extends Fragment { public void d(String e) { SLogs.d(this.getClass().getSimpleName() + " => " + e); } + + private boolean isFirstLoadData = true; + + @Override + public void onResume() { + super.onResume(); + if (isFirstLoadData) { + isFirstLoadData = false; + onFirstResume(); + } else { + onNonFirstResume(); + } + } + + public void onFirstResume() { + + } + + public void onNonFirstResume() { + + } } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java index f628842f6..ce5dee2b2 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/base/viewmodel/BaseViewModel.java @@ -260,15 +260,18 @@ public SeafException getExceptionByThrowable(Throwable throwable) throws IOExcep try { ResponseBody body = resp.errorBody(); if (body == null) { - return SeafException.unknownException; + return SeafException.networkException; } String result = body.string(); if (TextUtils.isEmpty(result)) { - return SeafException.unknownException; + return SeafException.networkException; } JSONObject json = Utils.parseJsonObject(result); + if (json == null) { + return SeafException.networkException; + } if (json.has("error_msg")) { String errorMsg = json.optString("error_msg"); diff --git a/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/AlbumBackupAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/AlbumBackupAdapter.java index be8a14aa7..08274687c 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/AlbumBackupAdapter.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/camera_upload/AlbumBackupAdapter.java @@ -10,6 +10,7 @@ import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.account.SupportAccountManager; +import com.seafile.seadroid2.framework.datastore.sp.AlbumBackupManager; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; @@ -83,6 +84,11 @@ public void onPerformSync(android.accounts.Account account, return; } + boolean isEnable = AlbumBackupManager.readBackupSwitch(); + if (!isEnable) { + return; + } + //start boolean isForce = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL); BackgroundJobManagerImpl.getInstance().scheduleMediaScanWorker(isForce); diff --git a/app/src/main/java/com/seafile/seadroid2/ui/folder_backup/FolderBackupSelectedPathActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/folder_backup/FolderBackupSelectedPathActivity.java index 28d9c8c3a..9779b6a3c 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/folder_backup/FolderBackupSelectedPathActivity.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/folder_backup/FolderBackupSelectedPathActivity.java @@ -1,8 +1,12 @@ package com.seafile.seadroid2.ui.folder_backup; import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.os.Bundle; +import android.os.IBinder; import android.text.TextUtils; import android.view.MenuItem; import android.view.View; @@ -14,12 +18,16 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.work.NetworkType; import com.blankj.utilcode.util.CollectionUtils; import com.chad.library.adapter4.QuickAdapterHelper; import com.seafile.seadroid2.R; import com.seafile.seadroid2.bottomsheetmenu.BottomSheetHelper; import com.seafile.seadroid2.bottomsheetmenu.BottomSheetMenuFragment; +import com.seafile.seadroid2.framework.file_monitor.FileSyncService; +import com.seafile.seadroid2.framework.util.SLogs; +import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; import com.seafile.seadroid2.ui.base.BaseActivity; import com.seafile.seadroid2.framework.datastore.sp.FolderBackupManager; @@ -31,6 +39,7 @@ public class FolderBackupSelectedPathActivity extends BaseActivity { private FolderBackupSelectedPathAdapter mAdapter; private QuickAdapterHelper helper; private String initialPathStr; + private FileSyncService fileSyncService; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -82,14 +91,31 @@ private void initAdapter() { private void showRepoBottomSheet(int position) { BottomSheetHelper.showSheet(this, R.menu.folder_backup_bottom_sheet_delete, menuItem -> { if (menuItem.getItemId() == R.id.delete) { - mAdapter.removeAt(position); - - List list = mAdapter.getItems(); - FolderBackupManager.writeBackupPaths(list); + deletePath(position); } }); } + private void deletePath(int position) { + //clear last scan time + String path = mAdapter.getItems().get(position); + FolderBackupManager.clearBackupPathLastScanTime(path); + + mAdapter.removeAt(position); + + List list = mAdapter.getItems(); + FolderBackupManager.writeBackupPaths(list); + + if (fileSyncService != null) { + fileSyncService.stopFolderMonitor(); + + fileSyncService.startFolderMonitor(); + } + + //restart + BackgroundJobManagerImpl.getInstance().restartFolderUploadWorker(); + } + private void showBottomDialog(String text) { new BottomSheetMenuFragment.Builder(this) .setTitle(text) @@ -135,4 +161,45 @@ public void onActivityResult(ActivityResult o) { initData(); } }); + + + private boolean isBound = false; + + private final ServiceConnection syncConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + FileSyncService.FileSyncBinder binder = (FileSyncService.FileSyncBinder) service; + fileSyncService = binder.getService(); + isBound = true; + SLogs.d("SettingsFragment: bond FileSyncService"); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + fileSyncService = null; + isBound = false; + SLogs.d("SettingsFragment: FileSyncService disconnected"); + } + }; + + private void bindService() { + if (!isBound) { + Intent syncIntent = new Intent(this, FileSyncService.class); + bindService(syncIntent, syncConnection, Context.BIND_AUTO_CREATE); + } + } + + private void unbindService() { + if (isBound) { + unbindService(syncConnection); + } + } + + @Override + public void onDestroy() { + + unbindService(); + + super.onDestroy(); + } } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java b/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java index 14fb2469a..8d755d834 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/main/MainActivity.java @@ -28,6 +28,8 @@ import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import androidx.viewpager2.widget.ViewPager2; +import androidx.work.Data; +import androidx.work.WorkInfo; import com.blankj.utilcode.util.ActivityUtils; import com.blankj.utilcode.util.CollectionUtils; @@ -53,6 +55,10 @@ import com.seafile.seadroid2.framework.util.Utils; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; import com.seafile.seadroid2.framework.file_monitor.FileSyncService; +import com.seafile.seadroid2.framework.worker.upload.FolderBackupScannerWorker; +import com.seafile.seadroid2.framework.worker.SupportWorkManager; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; import com.seafile.seadroid2.ui.account.AccountsActivity; import com.seafile.seadroid2.ui.adapter.ViewPager2Adapter; import com.seafile.seadroid2.ui.base.BaseActivity; @@ -129,7 +135,9 @@ protected void onCreate(Bundle savedInstanceState) { initOnBackPressedDispatcher(); initBottomNavigation(); initViewPager(); + initViewModel(); + initWorkerListener(); //service bindService(); @@ -367,6 +375,32 @@ public void onPageSelected(int position) { }); } + private void initWorkerListener() { + SupportWorkManager.getWorkManager() + .getWorkInfoByIdLiveData(FolderBackupScannerWorker.UID) + .observe(this, new Observer() { + @Override + public void onChanged(WorkInfo workInfo) { + if (null == workInfo) { + return; + } + + Data data = workInfo.getOutputData(); + String event = data.getString(TransferWorker.KEY_DATA_EVENT); + + if (TextUtils.isEmpty(event)) { + return; + } + + if (TransferEvent.EVENT_SCAN_END.equals(event)) { + if (syncService != null) { + syncService.startFolderMonitor(); + } + } + } + }); + } + private void initViewModel() { mainViewModel.getOnForceRefreshRepoListLiveData().observe(this, new Observer() { @Override diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java index 596d4fc34..f8fec260f 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoQuickFragment.java @@ -27,6 +27,7 @@ import androidx.lifecycle.ViewModelProvider; import androidx.media3.common.util.UnstableApi; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.work.Data; import androidx.work.WorkInfo; import com.blankj.utilcode.util.CollectionUtils; @@ -54,13 +55,13 @@ import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.util.Utils; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; -import com.seafile.seadroid2.framework.worker.DownloadWorker; +import com.seafile.seadroid2.framework.worker.download.DownloadWorker; import com.seafile.seadroid2.framework.worker.SupportWorkManager; import com.seafile.seadroid2.framework.worker.TransferEvent; import com.seafile.seadroid2.framework.worker.TransferWorker; -import com.seafile.seadroid2.framework.worker.UploadFileManuallyWorker; -import com.seafile.seadroid2.framework.worker.UploadFolderFileAutomaticallyWorker; -import com.seafile.seadroid2.framework.worker.UploadMediaFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFileManuallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker; import com.seafile.seadroid2.ui.WidgetUtils; import com.seafile.seadroid2.ui.base.fragment.BaseFragmentWithVM; import com.seafile.seadroid2.ui.dialog_fragment.CopyMoveDialogFragment; @@ -90,8 +91,10 @@ public class RepoQuickFragment extends BaseFragmentWithVM { private static final String KEY_REPO_SCROLL_POSITION = "repo_scroll_position"; private static final String KEY_REPO_LIST = "key_in_repo_list"; + private final int forceRefreshInterval = 1000 * 60 * 5;//5m + private final HashMap mRefreshStatusExpireTimeMap = new HashMap<>(); - private boolean isFirstLoadData = true; + private LayoutFrameSwipeRvBinding binding; private RepoQuickAdapter adapter; private LinearLayoutManager rvManager; @@ -146,17 +149,16 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat } @Override - public void onResume() { - super.onResume(); - d("load data:onResume"); - if (isFirstLoadData) { - isFirstLoadData = false; - d("load data:isFirstLoadData"); + public void onFirstResume() { + super.onFirstResume(); + loadData(true); + } + + @Override + public void onNonFirstResume() { + super.onNonFirstResume(); + if (isForce()) { loadData(true); - } else { - if (isForce()) { - loadData(true); - } } } @@ -322,9 +324,13 @@ public void onChanged(WorkInfo workInfo) { private void checkWorkInfo(WorkInfo workInfo) { if (workInfo != null && workInfo.getState().isFinished()) { - String transferState = workInfo.getOutputData().getString(TransferWorker.KEY_DATA_EVENT); - if (TransferEvent.EVENT_TRANSFERRED_WITH_DATA.equals(transferState)) { - loadData(true); + Data data = workInfo.getOutputData(); + String transferState = data.getString(TransferWorker.KEY_DATA_EVENT); +// int pendingTransferCount = data.getInt(TransferWorker.KEY_DATA_PARAM, -1); + String dataType = data.getString(TransferWorker.KEY_DATA_TYPE); + SLogs.e(dataType + " -> " + transferState); + if (TransferEvent.EVENT_FINISH.equals(transferState)) { + loadData(isForce()); } } } @@ -352,14 +358,13 @@ public void loadData() { public void loadData(boolean forceRefresh) { if (forceRefresh) { long now = TimeUtils.getNowMills(); - now += 1000 * 60 * 10;//10min + now += forceRefreshInterval; if (getNavContext().isInRepoList()) { mRefreshStatusExpireTimeMap.put(KEY_REPO_LIST, now); } else { String k = getNavContext().getRepoModel().repo_id + getNavContext().getNavPath(); mRefreshStatusExpireTimeMap.put(k, now); } - } // diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoService.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoService.java index 1f61c4a8a..2ffebabca 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoService.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoService.java @@ -33,6 +33,11 @@ public interface RepoService { @GET("api/v2.1/repos/{repo_id}/dir/?with_thumbnail=true") Single getDirents(@Path("repo_id") String repoId, @Query("p") String path); + + @GET("api/v2.1/repos/{repo_id}/dir/?with_thumbnail=true") + Call getDirentsCall(@Path("repo_id") String repoId, @Query("p") String path); + + @GET("api/v2.1/repos/{repo_id}/dir/?with_thumbnail=true") Call getDirentsSync(@Path("repo_id") String repoId, @Query("p") String path); diff --git a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java index fed85fe50..3da56d2d9 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/repo/RepoViewModel.java @@ -106,7 +106,9 @@ public void loadData(NavContext context, boolean forceRefresh) { } private void loadReposFromDB(Account account, boolean isForce) { - getRefreshLiveData().setValue(true); + if (isForce) { + getRefreshLiveData().setValue(true); + } Single> singleDB = AppDatabase.getInstance().repoDao().getListByAccount(account.getSignature()); addSingleDisposable(singleDB, new Consumer>() { diff --git a/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java index fdc1bc725..30102db51 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragment.java @@ -30,7 +30,6 @@ import androidx.preference.PreferenceFragmentCompat; import androidx.preference.SwitchPreferenceCompat; import androidx.work.Data; -import androidx.work.NetworkType; import androidx.work.WorkInfo; import com.blankj.utilcode.util.AppUtils; @@ -60,10 +59,10 @@ import com.seafile.seadroid2.framework.worker.SupportWorkManager; import com.seafile.seadroid2.framework.worker.TransferEvent; import com.seafile.seadroid2.framework.worker.TransferWorker; -import com.seafile.seadroid2.framework.worker.FolderBackupScannerWorker; -import com.seafile.seadroid2.framework.worker.UploadFolderFileAutomaticallyWorker; -import com.seafile.seadroid2.framework.worker.MediaBackupScannerWorker; -import com.seafile.seadroid2.framework.worker.UploadMediaFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.FolderBackupScannerWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.MediaBackupScannerWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker; import com.seafile.seadroid2.gesturelock.LockPatternUtils; import com.seafile.seadroid2.ui.camera_upload.CameraUploadConfigActivity; import com.seafile.seadroid2.ui.camera_upload.CameraUploadManager; @@ -242,27 +241,34 @@ private void checkScanWorkInfo(TransferDataSource dataSource, WorkInfo workInfo) return; } - Data progressData = workInfo.getProgress(); Data outData = workInfo.getOutputData(); + String outDataEvent = outData.getString(TransferWorker.KEY_DATA_EVENT); + String outDataType = outData.getString(TransferWorker.KEY_DATA_TYPE); + if (String.valueOf(TransferDataSource.ALBUM_BACKUP).equals(outDataType)) { + if (TransferEvent.EVENT_SCAN_END.equals(outDataEvent)) { + mCameraBackupState.setSummary(R.string.waiting); + return; + } + } else if (String.valueOf(TransferDataSource.FOLDER_BACKUP).equals(outDataType)) { + if (TransferEvent.EVENT_SCAN_END.equals(outDataEvent)) { + mFolderBackupState.setSummary(R.string.waiting); + return; + } + } + Data progressData = workInfo.getProgress(); String pDataEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); - String oDataEvent = outData.getString(TransferWorker.KEY_DATA_EVENT); - - if (TextUtils.isEmpty(oDataEvent) && TextUtils.isEmpty(pDataEvent)) { + if (TextUtils.isEmpty(pDataEvent)) { return; } if (TransferDataSource.ALBUM_BACKUP == dataSource) { if (TransferEvent.EVENT_SCANNING.equals(pDataEvent)) { mCameraBackupState.setSummary(R.string.is_scanning); - } else if (TransferEvent.EVENT_SCAN_END.equals(oDataEvent)) { - mCameraBackupState.setSummary(R.string.waiting); } } else if (TransferDataSource.FOLDER_BACKUP == dataSource) { if (TransferEvent.EVENT_SCANNING.equals(pDataEvent)) { mFolderBackupState.setSummary(R.string.is_scanning); - } else if (TransferEvent.EVENT_SCAN_END.equals(oDataEvent)) { - mFolderBackupState.setSummary(R.string.waiting); } } } @@ -273,34 +279,24 @@ private void doWorkInfoLiveData(WorkInfo workInfo) { } Data outData = workInfo.getOutputData(); - Data progressData = workInfo.getProgress(); - String outDataEvent = outData.getString(TransferWorker.KEY_DATA_EVENT); String outDataType = outData.getString(TransferWorker.KEY_DATA_TYPE); - if (!TextUtils.isEmpty(outDataEvent)) { - if (String.valueOf(TransferDataSource.ALBUM_BACKUP).equals(outDataType)) { - if (TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA.equals(outDataEvent)) { - mCameraBackupState.setSummary(R.string.settings_cuc_finish_title); - } else if (TransferEvent.EVENT_TRANSFERRED_WITH_DATA.equals(outDataEvent)) { - mCameraBackupState.setSummary(R.string.settings_cuc_finish_title); - } else if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(outDataEvent)) { - mCameraBackupState.setSummary(R.string.above_quota); - } - } else if (String.valueOf(TransferDataSource.FOLDER_BACKUP).equals(outDataType)) { - if (TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA.equals(outDataEvent)) { - mFolderBackupState.setSummary(R.string.folder_backup_waiting_state); - } else if (TransferEvent.EVENT_TRANSFERRED_WITH_DATA.equals(outDataEvent)) { - mFolderBackupState.setSummary(R.string.folder_backup_waiting_state); - } else if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(outDataEvent)) { - mFolderBackupState.setSummary(R.string.above_quota); - } + if (String.valueOf(TransferDataSource.ALBUM_BACKUP).equals(outDataType)) { + if (TransferEvent.EVENT_FINISH.equals(outDataEvent)) { + mCameraBackupState.setSummary(R.string.settings_cuc_finish_title); + return; + } + } else if (String.valueOf(TransferDataSource.FOLDER_BACKUP).equals(outDataType)) { + if (TransferEvent.EVENT_FINISH.equals(outDataEvent)) { + mFolderBackupState.setSummary(R.string.folder_backup_waiting_state); + return; } - - return; } + + Data progressData = workInfo.getProgress(); String dataType = progressData.getString(TransferWorker.KEY_DATA_TYPE); - String progressDataEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); + String progressEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); String progressFileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); if (TextUtils.isEmpty(dataType)) { @@ -308,16 +304,18 @@ private void doWorkInfoLiveData(WorkInfo workInfo) { } if (String.valueOf(TransferDataSource.ALBUM_BACKUP).equals(dataType)) { - if (TransferEvent.EVENT_TRANSFERRING.equals(progressDataEvent)) { + if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(progressEvent)) { + mCameraBackupState.setSummary(R.string.above_quota); + } else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) { viewModel.countAlbumBackupState(requireContext()); } } else if (String.valueOf(TransferDataSource.FOLDER_BACKUP).equals(dataType)) { - if (TransferEvent.EVENT_TRANSFERRING.equals(progressDataEvent)) { + if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(progressEvent)) { + mFolderBackupState.setSummary(R.string.above_quota); + } else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) { viewModel.countFolderBackupState(requireContext()); } } - - } private void loadData() { @@ -634,12 +632,7 @@ public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) refreshFolderBackNetworkMode(which); //restart - NetworkType networkType = NetworkType.UNMETERED; - if (FolderBackupManager.readDataPlanAllowed()) { - networkType = NetworkType.CONNECTED; - } - - BackgroundJobManagerImpl.getInstance().restartFolderUploadWorker(networkType); + BackgroundJobManagerImpl.getInstance().restartFolderUploadWorker(); } }); @@ -728,7 +721,7 @@ private void switchCameraWorker(boolean isChecked) { CameraUploadManager.getInstance().setCameraAccount(currentAccount); BackgroundJobManagerImpl.getInstance().restartMediaBackupWorker(true); - //firebase - event -login + //firebase - event - switch camera worker Bundle eventBundle = new Bundle(); eventBundle.putString(FirebaseAnalytics.Param.METHOD, "switchCameraWorker"); FirebaseAnalytics.getInstance(requireContext()).logEvent(AnalyticsEvent.ALBUM_BACKUP, eventBundle); @@ -749,7 +742,7 @@ private void refreshFolderBackupView(boolean isSync) { setFolderPreferencesVisible(isFolderAutomaticBackup); if (!isFolderAutomaticBackup) { - BackgroundJobManagerImpl.getInstance().cancelFolderWorker(); + BackgroundJobManagerImpl.getInstance().cancelFilesUploadWorker(); if (fileSyncService != null) { fileSyncService.stopFolderMonitor(); } @@ -772,7 +765,7 @@ private void refreshFolderBackupView(boolean isSync) { if (isSync && !CollectionUtils.isEmpty(pathList) && repoConfig != null) { if (fileSyncService != null) { - fileSyncService.startFolderMonitor(pathList); + fileSyncService.startFolderMonitor(); } BackgroundJobManagerImpl.getInstance().scheduleFolderBackupScannerWorker(true); diff --git a/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragmentViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragmentViewModel.java index ad0e4b6f4..7ab1a5f4a 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragmentViewModel.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/settings/SettingsFragmentViewModel.java @@ -20,8 +20,8 @@ import com.seafile.seadroid2.framework.datastore.StorageManager; import com.seafile.seadroid2.framework.http.IO; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; -import com.seafile.seadroid2.framework.worker.UploadFolderFileAutomaticallyWorker; -import com.seafile.seadroid2.framework.worker.UploadMediaFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker; import com.seafile.seadroid2.ui.account.AccountService; import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel; import com.seafile.seadroid2.ui.main.MainService; @@ -93,10 +93,6 @@ public void accept(AccountInfo accountInfo) throws Exception { } public void countFolderBackupState(Context context) { - countFolderBackupState(context, null); - } - - public void countFolderBackupState(Context context, String fileName) { Account account = SupportAccountManager.getInstance().getCurrentAccount(); @@ -118,11 +114,7 @@ public void accept(Integer s) throws Exception { if (workInfo != null && WorkInfo.State.ENQUEUED == workInfo.getState()) { folderBackupStateLiveData.setValue(context.getString(R.string.waiting)); } else { - if (TextUtils.isEmpty(fileName)) { - folderBackupStateLiveData.setValue(String.valueOf(s)); - } else { - folderBackupStateLiveData.setValue("(" + s + ") " + fileName); - } + folderBackupStateLiveData.setValue(String.valueOf(s)); } } } @@ -130,10 +122,6 @@ public void accept(Integer s) throws Exception { } public void countAlbumBackupState(Context context) { - countAlbumBackupState(context, null); - } - - public void countAlbumBackupState(Context context, String fileName) { Account account = SupportAccountManager.getInstance().getCurrentAccount(); Single folderBackupInProgressCountSingle = AppDatabase @@ -146,7 +134,7 @@ public void countAlbumBackupState(Context context, String fileName) { addSingleDisposable(folderBackupInProgressCountSingle, new Consumer() { @Override - public void accept(Integer s) throws Exception { + public void accept(Integer s) { if (s == 0) { albumBackupStateLiveData.setValue(context.getString(R.string.settings_cuc_finish_title)); } else { @@ -154,11 +142,7 @@ public void accept(Integer s) throws Exception { if (workInfo != null && WorkInfo.State.ENQUEUED == workInfo.getState()) { albumBackupStateLiveData.setValue(context.getString(R.string.waiting)); } else { - if (TextUtils.isEmpty(fileName)) { - albumBackupStateLiveData.setValue(String.valueOf(s)); - } else { - albumBackupStateLiveData.setValue("(" + s + ") " + fileName); - } + albumBackupStateLiveData.setValue(String.valueOf(s)); } } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/star/StarredQuickFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/star/StarredQuickFragment.java index 5e19cac2f..d514d3f03 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/star/StarredQuickFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/star/StarredQuickFragment.java @@ -94,19 +94,19 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat initViewModel(); } - private boolean isFirstLoadData = true; private boolean isForce = false; + @Override + public void onFirstResume() { + super.onFirstResume(); + reload(); + } + @Override public void onResume() { super.onResume(); - d("load data:onResume"); if (isForce) { reload(); - } else if (isFirstLoadData) { - isFirstLoadData = false; - d("load data:isFirstLoadData"); - reload(); } } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/DownloadListFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/DownloadListFragment.java index 7ca4ca69f..985d9e8d5 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/DownloadListFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/DownloadListFragment.java @@ -19,11 +19,10 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; -import com.seafile.seadroid2.framework.worker.DownloadWorker; +import com.seafile.seadroid2.framework.worker.download.DownloadWorker; import com.seafile.seadroid2.framework.worker.SupportWorkManager; import com.seafile.seadroid2.framework.worker.TransferEvent; import com.seafile.seadroid2.framework.worker.TransferWorker; -import com.seafile.seadroid2.framework.worker.UploadMediaFileAutomaticallyWorker; import java.util.List; @@ -70,19 +69,19 @@ private void doWorkInfoLiveData(TransferDataSource dataSource, WorkInfo workInfo } Data outData = workInfo.getOutputData(); - Data progressData = workInfo.getProgress(); - String outEvent = outData.getString(TransferWorker.KEY_DATA_EVENT); - String progressEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); + if (TransferEvent.EVENT_FINISH.equals(outEvent)) { + refreshData(); + return; + } - if (TransferEvent.EVENT_TRANSFERRED_WITH_DATA.equals(outEvent)) { - loadData(); - } else if (TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA.equals(outEvent)) { + Data progressData = workInfo.getProgress(); + String progressEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); - } else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) { + if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) { - String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_KEY); + String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_ID_KEY); String fileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); int percent = progressData.getInt(TransferWorker.KEY_DATA_PROGRESS, 0); long transferredSize = progressData.getLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, 0); @@ -91,11 +90,30 @@ private void doWorkInfoLiveData(TransferDataSource dataSource, WorkInfo workInfo SLogs.d("download: " + fileName + ", percent:" + percent + ", total_size:" + totalSize + ", dataSource: " + dataSource); if (TextUtils.equals(transferId, lastTransferId)) { - adapter.notifyProgressById(transferId, transferredSize, percent); + notifyProgressById(transferId, transferredSize, percent, progressEvent); } else { lastTransferId = transferId; - loadData(false); + } + } else if (TransferEvent.EVENT_TRANSFER_SUCCESS.equals(progressEvent)) { + String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_ID_KEY); + String fileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); + long transferredSize = progressData.getLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, 0); + long totalSize = progressData.getLong(TransferWorker.KEY_DATA_TOTAL_SIZE, 0); + + SLogs.d("download finish: " + fileName + ", total_size:" + totalSize + ", dataSource: " + dataSource); + + notifyProgressById(transferId, transferredSize, 100, progressEvent); + + } else if (TransferEvent.EVENT_TRANSFER_FAILED.equals(progressEvent)) { + String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_ID_KEY); + String fileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); + long transferredSize = progressData.getLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, 0); + long totalSize = progressData.getLong(TransferWorker.KEY_DATA_TOTAL_SIZE, 0); + + SLogs.d("download failed: " + fileName + ", dataSource: " + dataSource); + + notifyProgressById(transferId, transferredSize, 0, progressEvent); } } @@ -122,7 +140,7 @@ public void accept(Boolean aBoolean) throws Exception { dialog.dismiss(); - loadData(); + refreshData(); } }); } @@ -170,7 +188,7 @@ public void cancelAllTasks() { public void accept(Boolean aBoolean) throws Exception { ToastUtils.showLong(R.string.cancel_download); - loadData(); + refreshData(); } }); } @@ -191,7 +209,7 @@ public void onClick(DialogInterface dialog, int which) { public void accept(Boolean aBoolean) throws Exception { ToastUtils.showLong(R.string.deleted); - loadData(); + refreshData(); } }); } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java index f818c4f29..5bee44a5e 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListAdapter.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; public class TransferListAdapter extends BaseAdapter { private boolean actionModeOn; @@ -177,7 +178,7 @@ private void onBindHolder(TransferItemViewHolder holder, FileTransferEntity enti if (TransferResult.NO_RESULT == entity.transfer_result) { holder.binding.transferFileErrorState.setVisibility(View.GONE); holder.binding.transferFileErrorState.setText(null); - }else if (TransferResult.TRANSMITTED == entity.transfer_result) { + } else if (TransferResult.TRANSMITTED == entity.transfer_result) { holder.binding.transferFileErrorState.setVisibility(View.GONE); holder.binding.transferFileErrorState.setText(null); } else { @@ -206,20 +207,6 @@ private void onBindPayloadHolder(TransferItemViewHolder holder, FileTransferEnti holder.binding.transferFileProgressBar.setProgress(percent); } - public void notifyProgressById(String transferId, long transferredSize, int percent) { - int position = getPositionById(transferId); - if (position == -1) { - return; - } - - getItems().get(position).transferred_size = transferredSize; - - Bundle bundle = new Bundle(); - bundle.putInt(TransferWorker.KEY_DATA_PROGRESS, percent); - bundle.putLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, transferredSize); - notifyItemChanged(position, bundle); - } - public void notifyDataChanged(List list) { if (CollectionUtils.isEmpty(list)) { submitList(list); @@ -370,19 +357,6 @@ public boolean selectItemByMode(int position) { } - private int getPositionById(String id) { - if (CollectionUtils.isEmpty(getItems())) { - return -1; - } - - for (int i = 0; i < getItems().size(); i++) { - if (TextUtils.equals(id, getItems().get(i).uid)) { - return i; - } - } - return -1; - } - private int getSelectedPositionByMode() { for (int i = 0; i < getItems().size(); i++) { if (getItems().get(i).is_selected) { diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java index e3dbdeb63..5c7318781 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListFragment.java @@ -3,6 +3,7 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.util.Pair; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -14,12 +15,15 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.view.ActionMode; +import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; import com.blankj.utilcode.util.CollectionUtils; import com.blankj.utilcode.util.ToastUtils; import com.chad.library.adapter4.BaseQuickAdapter; import com.chad.library.adapter4.QuickAdapterHelper; +import com.chad.library.adapter4.loadState.trailing.TrailingLoadStateAdapter; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.seafile.seadroid2.R; import com.seafile.seadroid2.bottomsheetmenu.BottomSheetHelper; @@ -27,11 +31,17 @@ import com.seafile.seadroid2.databinding.LayoutFrameSwipeRvBinding; import com.seafile.seadroid2.framework.data.db.entities.FileTransferEntity; import com.seafile.seadroid2.framework.data.model.enums.TransferAction; +import com.seafile.seadroid2.framework.data.model.enums.TransferResult; +import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; +import com.seafile.seadroid2.framework.worker.TransferEvent; +import com.seafile.seadroid2.framework.worker.TransferWorker; +import com.seafile.seadroid2.ui.base.adapter.LogicLoadMoreAdapter; import com.seafile.seadroid2.ui.base.fragment.BaseFragment; import com.seafile.seadroid2.view.TipsViews; import java.util.List; +import java.util.Map; import io.reactivex.functions.Consumer; @@ -40,8 +50,9 @@ public abstract class TransferListFragment extends BaseFragment { protected TransferListAdapter adapter; private ActionMode actionMode; protected TransferActivity activity = null; - + private LinearLayoutManager layoutManager; private TransferListViewModel viewModel; + private Map positionMap; @Override public void onAttach(@NonNull Context context) { @@ -64,7 +75,8 @@ public TransferListViewModel getViewModel() { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = LayoutFrameSwipeRvBinding.inflate(inflater, container, false); - binding.swipeRefreshLayout.setOnRefreshListener(this::loadData); + binding.swipeRefreshLayout.setOnRefreshListener(this::refreshData); + layoutManager = (LinearLayoutManager) binding.rv.getLayoutManager(); return binding.getRoot(); } @@ -75,8 +87,12 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat initAdapter(); initViewModel(); + } - loadData(); + @Override + public void onFirstResume() { + super.onFirstResume(); + refreshData(); } private void initAdapter() { @@ -122,14 +138,23 @@ public boolean onLongClick(@NonNull BaseQuickAdapter base }); - QuickAdapterHelper helper = new QuickAdapterHelper.Builder(adapter).build(); +// LogicLoadMoreAdapter loadMoreAdapter = getLogicLoadMoreAdapter(); + + QuickAdapterHelper helper = new QuickAdapterHelper.Builder(adapter) + .build(); binding.rv.setAdapter(helper.getAdapter()); } private void initViewModel() { getViewModel().getRefreshLiveData().observe(getViewLifecycleOwner(), aBoolean -> binding.swipeRefreshLayout.setRefreshing(aBoolean)); - getViewModel().getFileTransferEntitiesLiveData().observe(getViewLifecycleOwner(), this::notifyDataChanged); + getViewModel().getFileTransferEntitiesLiveData().observe(getViewLifecycleOwner(), new Observer, List>>() { + @Override + public void onChanged(Pair, List> mapListPair) { + notifyDataChanged(mapListPair.second); + positionMap = mapListPair.first; + } + }); } public void showBottomSheet(FileTransferEntity entity) { @@ -183,7 +208,7 @@ public void accept(Boolean aBoolean) throws Exception { ToastUtils.showLong(R.string.deleted); dialog.dismiss(); - loadData(); + refreshData(); } }); } @@ -218,14 +243,57 @@ public void startContextualActionMode() { public abstract void restartSelectedItems(List list); - protected void loadData() { - loadData(true); + protected void refreshData() { + loadNext(true); } - protected void loadData(boolean isShowRefresh) { + private void loadNext(boolean isShowRefresh) { getViewModel().loadData(getTransferAction(), isShowRefresh); } + public void notifyProgressById(String transferId, long transferredSize, int percent, String event) { + if (positionMap == null) { + return; + } + + int position = positionMap.get(transferId).intValue(); + if (position == -1) { + return; + } + + if (TransferEvent.EVENT_TRANSFER_FAILED.equals(event)) { + adapter.getItems().get(position).transferred_size = transferredSize; + adapter.getItems().get(position).transfer_status = TransferStatus.FAILED; + } else if (TransferEvent.EVENT_TRANSFER_SUCCESS.equals(event)) { + adapter.getItems().get(position).transferred_size = transferredSize; + adapter.getItems().get(position).transfer_status = TransferStatus.SUCCEEDED; + } else if (TransferEvent.EVENT_TRANSFERRING.equals(event)) { + adapter.getItems().get(position).transferred_size = transferredSize; + adapter.getItems().get(position).transfer_status = TransferStatus.IN_PROGRESS; + } + +// if (isItemVisible(position)) { + Bundle bundle = new Bundle(); + bundle.putInt(TransferWorker.KEY_DATA_PROGRESS, percent); + bundle.putLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, transferredSize); + adapter.notifyItemChanged(position, bundle); +// } + } + + + public boolean isItemVisible(int position) { + + if (layoutManager == null) { + return false; + } + + int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); + int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); + + return position >= firstVisibleItemPosition && position <= lastVisibleItemPosition; + } + + private void notifyDataChanged(List list) { if (CollectionUtils.isEmpty(list)) { showEmptyTip(); @@ -246,7 +314,7 @@ private void showAdapterTip(int textRes) { adapter.submitList(null); TextView tipView = TipsViews.getTipTextView(requireContext()); tipView.setText(textRes); - tipView.setOnClickListener(v -> loadData()); + tipView.setOnClickListener(v -> refreshData()); adapter.setStateView(tipView); adapter.setStateViewEnable(true); } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListViewModel.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListViewModel.java index 85be6d519..5a0bb6edc 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListViewModel.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/TransferListViewModel.java @@ -1,5 +1,7 @@ package com.seafile.seadroid2.ui.transfer_list; +import android.util.Pair; + import androidx.lifecycle.MutableLiveData; import com.blankj.utilcode.util.CollectionUtils; @@ -14,13 +16,16 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferStatus; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; import com.seafile.seadroid2.framework.worker.SupportWorkManager; -import com.seafile.seadroid2.framework.worker.UploadFileManuallyWorker; -import com.seafile.seadroid2.framework.worker.UploadFolderFileAutomaticallyWorker; -import com.seafile.seadroid2.framework.worker.UploadMediaFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFileManuallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker; import com.seafile.seadroid2.ui.base.viewmodel.BaseViewModel; import com.seafile.seadroid2.framework.util.SLogs; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import io.reactivex.Completable; import io.reactivex.Single; @@ -33,9 +38,9 @@ public class TransferListViewModel extends BaseViewModel { - private MutableLiveData> mFileTransferEntitiesLiveData = new MutableLiveData<>(); + private final MutableLiveData, List>> mFileTransferEntitiesLiveData = new MutableLiveData<>(); - public MutableLiveData> getFileTransferEntitiesLiveData() { + public MutableLiveData, List>> getFileTransferEntitiesLiveData() { return mFileTransferEntitiesLiveData; } @@ -50,29 +55,57 @@ public void loadData(TransferAction transferAction, boolean isShowRefresh) { getRefreshLiveData().setValue(false); return; } + Single, List>> single = queryPageData(account, transferAction); - Single> single; - if (TransferAction.UPLOAD == transferAction) { - single = AppDatabase - .getInstance() - .fileTransferDAO() - .getUploadListAsync(account.getSignature()); - } else { - single = AppDatabase - .getInstance() - .fileTransferDAO() - .getDownloadListAsync(account.getSignature()); - } + addSingleDisposable(single, pair -> { + mFileTransferEntitiesLiveData.setValue(pair); + if (isShowRefresh) { + getRefreshLiveData().setValue(false); + } + }); + } - addSingleDisposable(single, new Consumer>() { + private Single, List>> queryPageData(Account account, TransferAction transferAction) { + return Single.create(new SingleOnSubscribe, List>>() { @Override - public void accept(List fileTransferEntities) throws Exception { - mFileTransferEntitiesLiveData.setValue(fileTransferEntities); + public void subscribe(SingleEmitter, List>> emitter) throws Exception { + int page = 1; + int pageSize = 500; + + List list = new ArrayList<>(); + while (true) { + int offset = (page - 1) * pageSize; + + List temp; + if (TransferAction.UPLOAD == transferAction) { + temp = AppDatabase + .getInstance() + .fileTransferDAO() + .getPageUploadListSync(account.getSignature(), pageSize, offset); + } else { + temp = AppDatabase + .getInstance() + .fileTransferDAO() + .getPageDownloadListSync(account.getSignature(), pageSize, offset); + } - if (isShowRefresh) { - getRefreshLiveData().setValue(false); + if (CollectionUtils.isEmpty(temp)) { + break; + } + + page++; + + list.addAll(temp); + } + + Map map = new HashMap<>(); + + for (int i = 0; i < list.size(); i++) { + map.put(list.get(i).uid, i); } + + emitter.onSuccess(new Pair<>(map, list)); } }); } diff --git a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java index ac56e073c..4af807178 100644 --- a/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/ui/transfer_list/UploadListFragment.java @@ -19,13 +19,12 @@ import com.seafile.seadroid2.framework.data.model.enums.TransferDataSource; import com.seafile.seadroid2.framework.util.SLogs; import com.seafile.seadroid2.framework.worker.BackgroundJobManagerImpl; -import com.seafile.seadroid2.framework.worker.DownloadWorker; import com.seafile.seadroid2.framework.worker.SupportWorkManager; import com.seafile.seadroid2.framework.worker.TransferEvent; import com.seafile.seadroid2.framework.worker.TransferWorker; -import com.seafile.seadroid2.framework.worker.UploadFileManuallyWorker; -import com.seafile.seadroid2.framework.worker.UploadFolderFileAutomaticallyWorker; -import com.seafile.seadroid2.framework.worker.UploadMediaFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFileManuallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadFolderFileAutomaticallyWorker; +import com.seafile.seadroid2.framework.worker.upload.UploadMediaFileAutomaticallyWorker; import java.util.List; @@ -92,20 +91,20 @@ private void doWorkInfoLiveData(TransferDataSource dataSource, WorkInfo workInfo } Data outData = workInfo.getOutputData(); - Data progressData = workInfo.getProgress(); - String outEvent = outData.getString(TransferWorker.KEY_DATA_EVENT); - String progressEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); + if (TransferEvent.EVENT_FINISH.equals(outEvent)) { + refreshData(); + return; + } - if (TransferEvent.EVENT_TRANSFERRED_WITH_DATA.equals(outEvent)) { - loadData(); - } else if (TransferEvent.EVENT_TRANSFERRED_WITHOUT_DATA.equals(outEvent)) { + Data progressData = workInfo.getProgress(); + String progressEvent = progressData.getString(TransferWorker.KEY_DATA_EVENT); - } else if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(outEvent)) { - loadData(); + if (TransferEvent.EVENT_CANCEL_OUT_OF_QUOTA.equals(progressEvent)) { + refreshData(); } else if (TransferEvent.EVENT_TRANSFERRING.equals(progressEvent)) { - String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_KEY); + String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_ID_KEY); String fileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); int percent = progressData.getInt(TransferWorker.KEY_DATA_PROGRESS, 0); long transferredSize = progressData.getLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, 0); @@ -115,12 +114,30 @@ private void doWorkInfoLiveData(TransferDataSource dataSource, WorkInfo workInfo if (TextUtils.equals(transferId, lastTransferId)) { - adapter.notifyProgressById(transferId, transferredSize, percent); + notifyProgressById(transferId, transferredSize, percent, progressEvent); } else { lastTransferId = transferId; - loadData(false); } + } else if (TransferEvent.EVENT_TRANSFER_SUCCESS.equals(progressEvent)) { + String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_ID_KEY); + String fileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); + long transferredSize = progressData.getLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, 0); + long totalSize = progressData.getLong(TransferWorker.KEY_DATA_TOTAL_SIZE, 0); + + SLogs.d("upload finish: " + fileName + ", total_size:" + totalSize + ", dataSource: " + dataSource); + + notifyProgressById(transferId, transferredSize, 100, progressEvent); + + } else if (TransferEvent.EVENT_TRANSFER_FAILED.equals(progressEvent)) { + String transferId = progressData.getString(TransferWorker.DATA_TRANSFER_ID_KEY); + String fileName = progressData.getString(TransferWorker.DATA_TRANSFER_NAME_KEY); + long transferredSize = progressData.getLong(TransferWorker.KEY_DATA_TRANSFERRED_SIZE, 0); + long totalSize = progressData.getLong(TransferWorker.KEY_DATA_TOTAL_SIZE, 0); + + SLogs.d("upload failed: " + fileName + ", total_size:" + totalSize + ", dataSource: " + dataSource); + + notifyProgressById(transferId, transferredSize, 0, progressEvent); } } @@ -142,7 +159,7 @@ public void accept(Boolean aBoolean) throws Exception { dialog.dismiss(); - loadData(); + refreshData(); } }); } @@ -176,7 +193,7 @@ public void cancelAllTasks() { public void accept(Boolean aBoolean) throws Exception { ToastUtils.showLong(R.string.upload_cancelled); - loadData(); + refreshData(); } }); } @@ -199,7 +216,7 @@ public void onClick(DialogInterface dialog, int which) { public void accept(Boolean aBoolean) throws Exception { ToastUtils.showLong(R.string.upload_cancelled); - loadData(); + refreshData(); } }); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3af98231b..eb4c760df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -582,6 +582,7 @@ Scanning Uploading Network unavailable + Network error Password is required. Password is too weak. diff --git a/build_count.txt b/build_count.txt index 301160a93..56a6051ca 100644 --- a/build_count.txt +++ b/build_count.txt @@ -1 +1 @@ -8 \ No newline at end of file +1 \ No newline at end of file