From b5a2adf44bf621557eec618059a141bc6a209704 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 00:03:37 +0100 Subject: [PATCH 001/138] Introduce rewritten auto upload --- build.gradle | 2 +- .../owncloud/android/datamodel/OCFile.java | 2 +- .../files/InstantUploadBroadcastReceiver.java | 2 +- .../services/FileAlterationMagicListener.java | 123 ++++++++++++++++++ .../services/SyncedFolderJobService.java | 2 +- .../observer/SyncedFolderObserver.java | 78 ----------- .../observer/SyncedFolderObserverService.java | 98 ++++++++++++-- .../android/ui/activity/DrawerActivity.java | 2 +- .../ui/activity/FileDisplayActivity.java | 4 +- .../android/ui/activity/Preferences.java | 4 +- .../android/utils/RecursiveFileObserver.java | 109 ---------------- 11 files changed, 217 insertions(+), 209 deletions(-) create mode 100644 src/com/owncloud/android/services/FileAlterationMagicListener.java delete mode 100644 src/com/owncloud/android/services/observer/SyncedFolderObserver.java delete mode 100644 src/com/owncloud/android/utils/RecursiveFileObserver.java diff --git a/build.gradle b/build.gradle index 786ae6e32631..db54a60534fe 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ dependencies { compile "com.android.support:appcompat-v7:${supportLibraryVersion}" compile 'com.getbase:floatingactionbutton:1.10.1' compile 'com.google.code.findbugs:annotations:2.0.1' - + compile group: 'commons-io', name: 'commons-io', version: '2.4' /// dependencies for local unit tests testCompile 'junit:junit:4.12' diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index b26067130045..928c5fde4bf9 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -262,7 +262,7 @@ public Uri getExposedFileUri(Context context) { return null; } if (mExposedFileUri == null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // TODO - use FileProvider with any Android version, with deeper testing -> 2.2.0 mExposedFileUri = Uri.parse( ContentResolver.SCHEME_FILE + "://" + WebdavUtils.encodePath(mLocalPath) diff --git a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java index da70627417bc..0f9428c421e3 100644 --- a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java +++ b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java @@ -58,7 +58,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { Log_OC.d(TAG, "Received: " + intent.getAction()); if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) { handleNewPictureAction(context, intent); diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java new file mode 100644 index 000000000000..076f957950a6 --- /dev/null +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -0,0 +1,123 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + *

+ * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.services; + +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; +import android.content.Context; +import android.os.PersistableBundle; + +import com.owncloud.android.MainApp; +import com.owncloud.android.datamodel.SyncedFolder; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.utils.FileStorageUtils; + +import org.apache.commons.io.monitor.FileAlterationListener; +import org.apache.commons.io.monitor.FileAlterationObserver; + +import java.io.File; +import java.util.Date; + +/** + * Magical file alteration listener + */ + +public class FileAlterationMagicListener implements FileAlterationListener { + + public static final String TAG = "FileAlterationMagicListener"; + + private Context context; + + private SyncedFolder syncedFolder; + + public FileAlterationMagicListener(SyncedFolder syncedFolder) { + super(); + + context = MainApp.getAppContext(); + this.syncedFolder = syncedFolder; + } + + @Override + public void onStart(FileAlterationObserver observer) { + + } + + @Override + public void onDirectoryCreate(File directory) { + + } + + @Override + public void onDirectoryChange(File directory) { + + } + + @Override + public void onDirectoryDelete(File directory) { + + } + + @Override + public void onFileCreate(File file) { + PersistableBundle bundle = new PersistableBundle(); + // TODO extract + bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); + bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( + syncedFolder.getRemotePath(), file.getName(), + new Date().getTime(), + syncedFolder.getSubfolderByDate())); + bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); + bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); + + JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + Long date = new Date().getTime(); + JobInfo job = new JobInfo.Builder( + date.intValue(), + new ComponentName(context, SyncedFolderJobService.class)) + .setRequiresCharging(syncedFolder.getChargingOnly()) + .setMinimumLatency(10000) + .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) + .setExtras(bundle) + .setPersisted(true) + .build(); + + Integer result = js.schedule(job); + if (result <= 0) { + Log_OC.d(TAG, "Job failed to start: " + result); + } + + } + + @Override + public void onFileChange(File file) { + } + + @Override + public void onFileDelete(File file) { + + } + + @Override + public void onStop(FileAlterationObserver observer) { + + } +} diff --git a/src/com/owncloud/android/services/SyncedFolderJobService.java b/src/com/owncloud/android/services/SyncedFolderJobService.java index 0fb7fd1101f6..3a27c73680f7 100644 --- a/src/com/owncloud/android/services/SyncedFolderJobService.java +++ b/src/com/owncloud/android/services/SyncedFolderJobService.java @@ -35,7 +35,6 @@ import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.operations.UploadFileOperation; -import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; import java.io.File; @@ -72,6 +71,7 @@ public boolean onStartJob(JobParameters params) { String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(file.getAbsolutePath()); FileUploader.UploadRequester requester = new FileUploader.UploadRequester(); + requester.uploadNewFile( context, account, diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserver.java b/src/com/owncloud/android/services/observer/SyncedFolderObserver.java deleted file mode 100644 index 82a826c5fc00..000000000000 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserver.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.owncloud.android.services.observer; - -import android.annotation.TargetApi; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; -import android.content.Context; -import android.os.Build; -import android.os.FileObserver; -import android.os.PersistableBundle; -import android.util.Log; - -import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.SyncedFolder; -import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.services.SyncedFolderJobService; -import com.owncloud.android.utils.FileStorageUtils; -import com.owncloud.android.utils.RecursiveFileObserver; - -import java.io.File; -import java.util.Date; - -class SyncedFolderObserver extends RecursiveFileObserver { - - private Context context; - - public static final String TAG = "SyncedFolderObserver"; - private SyncedFolder syncedFolder; - - - public SyncedFolderObserver(SyncedFolder syncedFolder) { - super(syncedFolder.getLocalPath(), FileObserver.CREATE + FileObserver.MOVED_TO); - - context = MainApp.getAppContext(); - this.syncedFolder = syncedFolder; - Log_OC.d("SyncedFolderObserver", "Started watching: " + syncedFolder.getLocalPath()); - } - - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public void onEvent(int event, String path) { - Log.d(TAG, "Event: " + event + " Path: " + path); - - File temp = new File(path); - - // do not upload "null"-files, test if file exists and is a real file - if (!temp.getName().equalsIgnoreCase("null") && temp.isFile() && !temp.getName().endsWith(".tmp")) { - PersistableBundle bundle = new PersistableBundle(); - // TODO extract - bundle.putString(SyncedFolderJobService.LOCAL_PATH, path); - bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( - syncedFolder.getRemotePath(), temp.getName(), - new Date().getTime(), - syncedFolder.getSubfolderByDate())); - bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); - bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); - - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - Long date = new Date().getTime(); - JobInfo job = new JobInfo.Builder( - date.intValue(), - new ComponentName(context, SyncedFolderJobService.class)) - .setRequiresCharging(syncedFolder.getChargingOnly()) - .setMinimumLatency(10000) - .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) - .setExtras(bundle) - .setPersisted(true) - .build(); - - Integer result = js.schedule(job); - if (result <= 0) { - Log_OC.d(TAG, "Job failed to start: " + result); - } - } - } -} diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 570c810e91a5..c2d2e53e9b94 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -1,3 +1,24 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * At least some parts are Copyright (C) 2017 Mario Danic + * Those parts are under the following licence: + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + *

+ * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package com.owncloud.android.services.observer; import android.app.Service; @@ -9,14 +30,22 @@ import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.services.FileAlterationMagicListener; + +import org.apache.commons.io.monitor.FileAlterationMonitor; +import org.apache.commons.io.monitor.FileAlterationObserver; +import java.io.File; +import java.io.FileFilter; import java.util.HashMap; public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; private SyncedFolderProvider mProvider; - private HashMap syncedFolderMap = new HashMap<>(); + private HashMap syncedFolderMap = new HashMap<>(); private final IBinder mBinder = new SyncedFolderObserverBinder(); + private FileAlterationMonitor monitor; + private FileFilter fileFilter; @Override public void onCreate() { @@ -25,13 +54,32 @@ public void onCreate() { @Override public int onStartCommand(Intent intent, int flags, int startId) { + monitor = new FileAlterationMonitor(); + fileFilter = new FileFilter() { + @Override + public boolean accept(File pathname) { + if (pathname.getName().startsWith(".")) { + return false; + } + + return true; + } + }; Log_OC.d(TAG, "start"); for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { - if (syncedFolder.isEnabled()) { + if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - SyncedFolderObserver observer = new SyncedFolderObserver(syncedFolder); - observer.startWatching(); - syncedFolderMap.put(syncedFolder.getLocalPath(), observer); + + FileAlterationObserver observer = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); + observer.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(observer); + try { + monitor.start(); + syncedFolderMap.put(syncedFolder.getLocalPath(), observer); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onStartCommand"); + } + } } @@ -40,8 +88,13 @@ public int onStartCommand(Intent intent, int flags, int startId) { @Override public void onDestroy() { - for (SyncedFolderObserver observer : syncedFolderMap.values()) { - observer.stopWatching(); + for (FileAlterationObserver observer : syncedFolderMap.values()) { + monitor.removeObserver(observer); + try { + observer.destroy(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onDestroy"); + } syncedFolderMap.remove(observer); } } @@ -49,23 +102,42 @@ public void onDestroy() { /** * Restart oberver if it is enabled * If syncedFolder exists already, use it, otherwise create new observer + * * @param syncedFolder */ - public void restartObserver(SyncedFolder syncedFolder){ + + public void restartObserver(SyncedFolder syncedFolder) { + FileAlterationObserver fileAlterationObserver; if (syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { Log_OC.d(TAG, "stop observer: " + syncedFolder.getLocalPath()); - syncedFolderMap.get(syncedFolder.getLocalPath()).stopWatching(); + fileAlterationObserver = syncedFolderMap.get(syncedFolder.getLocalPath()); + monitor.removeObserver(fileAlterationObserver); + try { + fileAlterationObserver.destroy(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onDestroy"); + } syncedFolderMap.remove(syncedFolder.getLocalPath()); } if (syncedFolder.isEnabled()) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); if (syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { - syncedFolderMap.get(syncedFolder.getLocalPath()).startWatching(); + fileAlterationObserver = syncedFolderMap.get(syncedFolder.getLocalPath()); + if (fileAlterationObserver.getListeners() == null) { + fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + } + monitor.addObserver(fileAlterationObserver); } else { - SyncedFolderObserver observer = new SyncedFolderObserver(syncedFolder); - observer.startWatching(); - syncedFolderMap.put(syncedFolder.getLocalPath(), observer); + fileAlterationObserver = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); + fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(fileAlterationObserver); + try { + syncedFolderMap.put(syncedFolder.getLocalPath(), fileAlterationObserver); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong on RestartObserver"); + } + } } } diff --git a/src/com/owncloud/android/ui/activity/DrawerActivity.java b/src/com/owncloud/android/ui/activity/DrawerActivity.java index faf6ccb2b5a3..b7c456fa83a6 100644 --- a/src/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/src/com/owncloud/android/ui/activity/DrawerActivity.java @@ -176,7 +176,7 @@ protected void setupDrawer() { setupQuotaElement(); // show folder sync menu item only for Android 7+ - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) { mNavigationView.getMenu().removeItem(R.id.nav_folder_sync); } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 6e96cc246bd6..51f19ecf1760 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -256,8 +256,8 @@ public void onClick(View v) { * Opens a pop up info for the new instant upload and disabled the old instant upload. */ private void upgradeNotificationForInstantUpload() { - // check for Android 7+ if legacy instant upload is activated --> disable + show info - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && + // check for Android 5+ if legacy instant upload is activated --> disable + show info + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (PreferenceManager.instantPictureUploadEnabled(this) || PreferenceManager.instantPictureUploadEnabled(this))) { diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index bda0ca12587c..9db1fdb4aeec 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -368,8 +368,8 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { mPrefInstantUploadCategory = (PreferenceCategory) findPreference("instant_uploading_category"); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - // Instant upload via preferences on pre Android Nougat + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + // Instant upload via preferences on pre pre Lollipop mPrefInstantUploadPath = findPreference("instant_upload_path"); if (mPrefInstantUploadPath != null) { diff --git a/src/com/owncloud/android/utils/RecursiveFileObserver.java b/src/com/owncloud/android/utils/RecursiveFileObserver.java deleted file mode 100644 index b482882c43f6..000000000000 --- a/src/com/owncloud/android/utils/RecursiveFileObserver.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * ownCloud Android client application - * - * Copyright (C) 2012 Bartek Przybylski - * Copyright (C) 2015 ownCloud Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package com.owncloud.android.utils; - -import android.os.FileObserver; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -public class RecursiveFileObserver extends FileObserver { - - private final List mObservers = new ArrayList<>(); - private boolean watching = false; - private String mPath; - private int mMask; - - public RecursiveFileObserver(String path) { - this(path, ALL_EVENTS); - } - - public RecursiveFileObserver(String path, int mask) { - super(path, mask); - mPath = path; - mMask = mask; - } - - @Override - public void startWatching() { - if (watching) { - return; - } - watching = true; - final Stack stack = new Stack(); - stack.push(mPath); - - while (!stack.empty()) { - String parent = stack.pop(); - mObservers.add(new SingleFileObserver(parent, mMask)); - File path = new File(parent); - File[] files = path.listFiles(); - if (files == null) { - continue; - } - for (final File file : files) { - if (file.isDirectory() && !file.getName().equals(".") - && !file.getName().equals("..")) { - stack.push(file.getPath()); - } - } - } - for (int i = 0; i < mObservers.size(); i++) { - mObservers.get(i).startWatching(); - } - } - - @Override - public void stopWatching() { - if (!watching) { - return; - } - - for (int i = 0; i < mObservers.size(); ++i) { - mObservers.get(i).stopWatching(); - } - mObservers.clear(); - watching = false; - } - - @Override - public void onEvent(int event, String path) { - - } - - private class SingleFileObserver extends FileObserver { - private String mPath; - - SingleFileObserver(String path, int mask) { - super(path, mask); - mPath = path; - } - - @Override - public void onEvent(int event, String path) { - String newPath = mPath + "/" + path; - RecursiveFileObserver.this.onEvent(event, newPath); - } - - } -} From 4151767d20238827a4d89493daadb4d0406b27dd Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 00:07:15 +0100 Subject: [PATCH 002/138] Revert a typo --- src/com/owncloud/android/datamodel/OCFile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 928c5fde4bf9..b26067130045 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -262,7 +262,7 @@ public Uri getExposedFileUri(Context context) { return null; } if (mExposedFileUri == null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { // TODO - use FileProvider with any Android version, with deeper testing -> 2.2.0 mExposedFileUri = Uri.parse( ContentResolver.SCHEME_FILE + "://" + WebdavUtils.encodePath(mLocalPath) From 699ca263cceb184119d373ec7fb9b39e252677ae Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 00:10:06 +0100 Subject: [PATCH 003/138] Update a comment --- src/com/owncloud/android/ui/activity/DrawerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/ui/activity/DrawerActivity.java b/src/com/owncloud/android/ui/activity/DrawerActivity.java index b7c456fa83a6..e948811f2d0e 100644 --- a/src/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/src/com/owncloud/android/ui/activity/DrawerActivity.java @@ -175,7 +175,7 @@ protected void setupDrawer() { setupQuotaElement(); - // show folder sync menu item only for Android 7+ + // show folder sync menu item only for Android 5+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) { mNavigationView.getMenu().removeItem(R.id.nav_folder_sync); } From 13b864aaae87a385f114fd1c03d522e8814954e3 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 00:23:06 +0100 Subject: [PATCH 004/138] Enable menu item on 5.0 --- src/com/owncloud/android/ui/activity/DrawerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/ui/activity/DrawerActivity.java b/src/com/owncloud/android/ui/activity/DrawerActivity.java index e948811f2d0e..107617139d5a 100644 --- a/src/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/src/com/owncloud/android/ui/activity/DrawerActivity.java @@ -176,7 +176,7 @@ protected void setupDrawer() { setupQuotaElement(); // show folder sync menu item only for Android 5+ - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { mNavigationView.getMenu().removeItem(R.id.nav_folder_sync); } } From e4f483c8bb799eb7c1f741f50bd5b8813fd5f4a0 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 01:57:14 +0100 Subject: [PATCH 005/138] Silence codacy --- .../services/FileAlterationMagicListener.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 076f957950a6..2336700df1b5 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -57,22 +57,22 @@ public FileAlterationMagicListener(SyncedFolder syncedFolder) { @Override public void onStart(FileAlterationObserver observer) { - + // This method is intentionally empty } @Override public void onDirectoryCreate(File directory) { - + // This method is intentionally empty } @Override public void onDirectoryChange(File directory) { - + // This method is intentionally empty } @Override public void onDirectoryDelete(File directory) { - + // This method is intentionally empty } @Override @@ -109,15 +109,16 @@ public void onFileCreate(File file) { @Override public void onFileChange(File file) { + // This method is intentionally empty } @Override public void onFileDelete(File file) { - + // This method is intentionally empty } @Override public void onStop(FileAlterationObserver observer) { - + // This method is intentionally empty } } From 8051c67da4e09ffc51c4f88a99c1c92100b1af45 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 11:35:04 +0100 Subject: [PATCH 006/138] Remove strange

stuff --- .../android/services/FileAlterationMagicListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 2336700df1b5..3bae7ef81aa1 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -3,17 +3,17 @@ * * @author Mario Danic * Copyright (C) 2017 Mario Danic - *

+ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. - *

+ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - *

+ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ From 07981f00543bc29a31a87f7bbcea0bfce771a442 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 3 Feb 2017 11:38:40 +0100 Subject: [PATCH 007/138] Update copyrights --- .../android/services/FileAlterationMagicListener.java | 2 +- .../services/observer/SyncedFolderObserverService.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 3bae7ef81aa1..1b9badbecc82 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -13,7 +13,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index c2d2e53e9b94..ba1d1c370ba9 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -1,9 +1,11 @@ /** * Nextcloud Android client application * + * @author Tobias Kaminsky + * @author Andy Scherzinger * @author Mario Danic - * At least some parts are Copyright (C) 2017 Mario Danic - * Those parts are under the following licence: + * Copyright (C) 2016 Tobias Kaminsky, Andy Scherzinger + * Copyright (C) 2017 Mario Danic *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -18,7 +20,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - package com.owncloud.android.services.observer; import android.app.Service; From 197370535624b2eb2bc38667aafbda911ca72f04 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sat, 4 Feb 2017 23:28:33 +0100 Subject: [PATCH 008/138] Small bugfix --- .../observer/SyncedFolderObserverService.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index ba1d1c370ba9..9991c94265a5 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -59,11 +59,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { - if (pathname.getName().startsWith(".")) { - return false; - } - - return true; + return !pathname.getName().startsWith("."); } }; Log_OC.d(TAG, "start"); @@ -74,16 +70,17 @@ public boolean accept(File pathname) { FileAlterationObserver observer = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); observer.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(observer); - try { - monitor.start(); - syncedFolderMap.put(syncedFolder.getLocalPath(), observer); - } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong at onStartCommand"); - } - + syncedFolderMap.put(syncedFolder.getLocalPath(), observer); } } + try { + monitor.start(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onStartCommand"); + } + + return Service.START_NOT_STICKY; } From 4e9022243919b7de680a13588f04394d4c144c17 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 00:07:10 +0100 Subject: [PATCH 009/138] Fix a bug with SyncedFolderProvider --- .../android/datamodel/SyncedFolderProvider.java | 2 +- .../android/ui/activity/FolderSyncActivity.java | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java index 8e3740cf3036..425bf912ff21 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -165,7 +165,7 @@ public SyncedFolder findByLocalPath(String localPath) { Cursor cursor = mContentResolver.query( ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS, null, - ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_LOCAL_PATH + "==" + localPath, + ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_LOCAL_PATH + "== \"" + localPath + "\"", null, null ); diff --git a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java index a405e7ef65f9..4630ab0be70f 100644 --- a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java +++ b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java @@ -323,9 +323,13 @@ public void showFiles(boolean onDeviceOnly) { @Override public void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) { if (syncedFolderDisplayItem.getId() > UNPERSISTED_ID) { - mSyncedFolderProvider.updateFolderSyncEnabled(syncedFolderDisplayItem.getId(), syncedFolderDisplayItem.isEnabled()); + mSyncedFolderProvider.updateFolderSyncEnabled(syncedFolderDisplayItem.getId(), + syncedFolderDisplayItem.isEnabled()); } else { - mSyncedFolderProvider.storeFolderSync(syncedFolderDisplayItem); + long storedId = mSyncedFolderProvider.storeFolderSync(syncedFolderDisplayItem); + if (storedId != -1) { + syncedFolderDisplayItem.setId(storedId); + } } } @@ -362,7 +366,11 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) { if (syncedFolder.getId() == UNPERSISTED_ID) { // newly set up folder sync config - mSyncedFolderProvider.storeFolderSync(item); + long storedId = mSyncedFolderProvider.storeFolderSync(item); + if (storedId != -1) { + item.setId(storedId); + } + } else { // existing synced folder setup to be updated mSyncedFolderProvider.updateSyncFolder(item); From 7806ff2041bc52c2169d6e31f6d1a83669aa1c74 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 00:18:47 +0100 Subject: [PATCH 010/138] Ignore temporary files --- .../android/services/observer/SyncedFolderObserverService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 9991c94265a5..88d4ed1d2a91 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -59,7 +59,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { - return !pathname.getName().startsWith("."); + return !pathname.getName().startsWith(".") && !pathname.getAbsolutePath().endsWith(".tmp"); } }; Log_OC.d(TAG, "start"); From 9e44de98969c7ab1a3290cf8d9e57b802983a277 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 01:23:39 +0100 Subject: [PATCH 011/138] First step towards list persistance --- .../observer/FileAlterationMagicObserver.java | 62 +++++++++++++++++++ .../observer/SyncedFolderObserverService.java | 21 ++++++- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java new file mode 100644 index 000000000000..0b41c2e62fc7 --- /dev/null +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -0,0 +1,62 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.services.observer; + +import org.apache.commons.io.IOCase; +import org.apache.commons.io.monitor.FileAlterationObserver; +import org.apache.commons.io.monitor.FileEntry; + +import java.io.File; +import java.io.FileFilter; + +/** + * Magical file observer + */ + +public class FileAlterationMagicObserver extends FileAlterationObserver { + + public FileAlterationMagicObserver(String directoryName) { + super(directoryName); + } + + public FileAlterationMagicObserver(String directoryName, FileFilter fileFilter) { + super(directoryName, fileFilter); + } + + public FileAlterationMagicObserver(String directoryName, FileFilter fileFilter, IOCase caseSensitivity) { + super(directoryName, fileFilter, caseSensitivity); + } + + public FileAlterationMagicObserver(File directory) { + super(directory); + } + + public FileAlterationMagicObserver(File directory, FileFilter fileFilter) { + super(directory, fileFilter); + } + + public FileAlterationMagicObserver(File directory, FileFilter fileFilter, IOCase caseSensitivity) { + super(directory, fileFilter, caseSensitivity); + } + + public FileAlterationMagicObserver(FileEntry rootEntry, FileFilter fileFilter, IOCase caseSensitivity) { + super(rootEntry, fileFilter, caseSensitivity); + } +} diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 88d4ed1d2a91..c3d7f6d581d5 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -35,9 +35,11 @@ import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; +import org.apache.commons.io.monitor.FileEntry; import java.io.File; import java.io.FileFilter; +import java.lang.reflect.Field; import java.util.HashMap; public class SyncedFolderObserverService extends Service { @@ -62,12 +64,29 @@ public boolean accept(File pathname) { return !pathname.getName().startsWith(".") && !pathname.getAbsolutePath().endsWith(".tmp"); } }; + + FileEntry rootEntry; + Log_OC.d(TAG, "start"); for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - FileAlterationObserver observer = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); + Field f = null; + try { + observer.initialize(); + f = observer.getClass().getDeclaredField("rootEntry"); + f.setAccessible(true); + rootEntry = (FileEntry) f.get(observer); + observer = new FileAlterationMagicObserver(rootEntry, fileFilter, null); + } catch (NoSuchFieldException e) { + Log_OC.d(TAG, "Failed getting private field rootEntry via NoSuchFieldException"); + } catch (IllegalAccessException e) { + Log_OC.d(TAG, "Failed getting private field rootEntry via IllegalAccessException"); + } catch (Exception e) { + Log_OC.d(TAG, "Failed getting an observer to intialize"); + } + observer.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(observer); syncedFolderMap.put(syncedFolder.getLocalPath(), observer); From a24d14f57ceb09d88e08818487c042122520e8c2 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 03:22:48 +0100 Subject: [PATCH 012/138] Preparation for persistance --- .../observer/FileAlterationMagicObserver.java | 62 ------------------- .../observer/SyncedFolderObserverService.java | 32 +++++++++- 2 files changed, 30 insertions(+), 64 deletions(-) delete mode 100644 src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java deleted file mode 100644 index 0b41c2e62fc7..000000000000 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Nextcloud Android client application - * - * @author Mario Danic - * Copyright (C) 2017 Mario Danic - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.services.observer; - -import org.apache.commons.io.IOCase; -import org.apache.commons.io.monitor.FileAlterationObserver; -import org.apache.commons.io.monitor.FileEntry; - -import java.io.File; -import java.io.FileFilter; - -/** - * Magical file observer - */ - -public class FileAlterationMagicObserver extends FileAlterationObserver { - - public FileAlterationMagicObserver(String directoryName) { - super(directoryName); - } - - public FileAlterationMagicObserver(String directoryName, FileFilter fileFilter) { - super(directoryName, fileFilter); - } - - public FileAlterationMagicObserver(String directoryName, FileFilter fileFilter, IOCase caseSensitivity) { - super(directoryName, fileFilter, caseSensitivity); - } - - public FileAlterationMagicObserver(File directory) { - super(directory); - } - - public FileAlterationMagicObserver(File directory, FileFilter fileFilter) { - super(directory, fileFilter); - } - - public FileAlterationMagicObserver(File directory, FileFilter fileFilter, IOCase caseSensitivity) { - super(directory, fileFilter, caseSensitivity); - } - - public FileAlterationMagicObserver(FileEntry rootEntry, FileFilter fileFilter, IOCase caseSensitivity) { - super(rootEntry, fileFilter, caseSensitivity); - } -} diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index c3d7f6d581d5..29007746f469 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -23,9 +23,11 @@ package com.owncloud.android.services.observer; import android.app.Service; +import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; +import android.support.v4.util.Pair; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; @@ -39,7 +41,12 @@ import java.io.File; import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.HashMap; public class SyncedFolderObserverService extends Service { @@ -58,6 +65,7 @@ public void onCreate() { @Override public int onStartCommand(Intent intent, int flags, int startId) { monitor = new FileAlterationMonitor(); + fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { @@ -67,18 +75,22 @@ public boolean accept(File pathname) { FileEntry rootEntry; + FileOutputStream fos = null; + ArrayList> pairArrayList = new ArrayList<>(); + Log_OC.d(TAG, "start"); for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); FileAlterationObserver observer = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); - Field f = null; + Field f; try { observer.initialize(); f = observer.getClass().getDeclaredField("rootEntry"); f.setAccessible(true); rootEntry = (FileEntry) f.get(observer); - observer = new FileAlterationMagicObserver(rootEntry, fileFilter, null); + Pair pair = new Pair<>(syncedFolder, rootEntry); + pairArrayList.add(pair); } catch (NoSuchFieldException e) { Log_OC.d(TAG, "Failed getting private field rootEntry via NoSuchFieldException"); } catch (IllegalAccessException e) { @@ -93,6 +105,22 @@ public boolean accept(File pathname) { } } + try { + fos = MainApp.getAppContext().openFileOutput("nc_sync_persistance.persist", Context.MODE_PRIVATE); + ObjectOutputStream os = new ObjectOutputStream(fos); + for (int i = 0; i < pairArrayList.size(); i++) { + os.writeObject(pairArrayList.get(i)); + } + os.close(); + fos.close(); + } catch (FileNotFoundException e) { + Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); + } catch (IOException e) { + Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via IOException"); + } + + + try { monitor.start(); } catch (Exception e) { From 8a978a28ceb3f85e1de894b521747d3e9ca55c32 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 05:02:23 +0100 Subject: [PATCH 013/138] Move to approach without reflection --- .../observer/FileAlterationMagicObserver.java | 343 ++++++++++++++++++ .../observer/SyncedFolderObserverService.java | 19 +- 2 files changed, 348 insertions(+), 14 deletions(-) create mode 100644 src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java new file mode 100644 index 000000000000..c7b92a6235e7 --- /dev/null +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -0,0 +1,343 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Modified a bit by Mario Danic + * Changes are Copyright (C) 2017 Mario Danic + * + * Those changes are under the following licence: + * + * * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.services.observer; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.comparator.NameFileComparator; +import org.apache.commons.io.monitor.FileAlterationListener; +import org.apache.commons.io.monitor.FileAlterationObserver; +import org.apache.commons.io.monitor.FileEntry; + +import java.io.File; +import java.io.FileFilter; +import java.io.Serializable; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class FileAlterationMagicObserver extends FileAlterationObserver implements Serializable { + + private static final long serialVersionUID = 1185122225658782848L; + private final List listeners = new CopyOnWriteArrayList<>(); + private FileEntry rootEntry; + private FileFilter fileFilter; + private Comparator comparator; + + static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; + + + public FileAlterationMagicObserver(File directory, FileFilter fileFilter) { + super(directory, fileFilter); + + this.rootEntry = new FileEntry(directory); + this.fileFilter = fileFilter; + comparator = NameFileComparator.NAME_SYSTEM_COMPARATOR; + } + + /** + * Return the directory being observed. + * + * @return the directory being observed + */ + public File getDirectory() { + return rootEntry.getFile(); + } + + /** + * Return the fileFilter. + * + * @return the fileFilter + * @since 2.1 + */ + public FileFilter getFileFilter() { + return fileFilter; + } + + public FileEntry getRootEntry() { + return rootEntry; + } + + public void setRootEntry(FileEntry rootEntry) { + this.rootEntry = rootEntry; + } + + /** + * Add a file system listener. + * + * @param listener The file system listener + */ + public void addListener(final FileAlterationListener listener) { + if (listener != null) { + listeners.add(listener); + } + } + + /** + * Remove a file system listener. + * + * @param listener The file system listener + */ + public void removeListener(final FileAlterationListener listener) { + if (listener != null) { + while (listeners.remove(listener)) { + } + } + } + + /** + * Returns the set of registered file system listeners. + * + * @return The file system listeners + */ + public Iterable getListeners() { + return listeners; + } + + /** + * Does nothing - hack for the monitor + * + * + */ + public void initialize() { + } + + + /** + * Initializes everything + * + * @throws Exception if an error occurs + */ + public void init() throws Exception { + rootEntry.refresh(rootEntry.getFile()); + final FileEntry[] children = doListFiles(rootEntry.getFile(), rootEntry); + rootEntry.setChildren(children); + } + + + /** + * Final processing. + * + * @throws Exception if an error occurs + */ + public void destroy() throws Exception { + } + + /** + * Check whether the file and its chlidren have been created, modified or deleted. + */ + public void checkAndNotify() { + + /* fire onStart() */ + for (final FileAlterationListener listener : listeners) { + listener.onStart(this); + } + + /* fire directory/file events */ + final File rootFile = rootEntry.getFile(); + if (rootFile.exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile)); + } else if (rootEntry.isExists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + } else { + // Didn't exist and still doesn't + } + + /* fire onStop() */ + for (final FileAlterationListener listener : listeners) { + listener.onStop(this); + } + } + + /** + * Compare two file lists for files which have been created, modified or deleted. + * + * @param parent The parent entry + * @param previous The original list of files + * @param files The current list of files + */ + private void checkAndNotify(final FileEntry parent, final FileEntry[] previous, final File[] files) { + int c = 0; + final FileEntry[] current = files.length > 0 ? new FileEntry[files.length] : EMPTY_ENTRIES; + for (final FileEntry entry : previous) { + while (c < files.length && comparator.compare(entry.getFile(), files[c]) > 0) { + current[c] = createFileEntry(parent, files[c]); + doCreate(current[c]); + c++; + } + if (c < files.length && comparator.compare(entry.getFile(), files[c]) == 0) { + doMatch(entry, files[c]); + checkAndNotify(entry, entry.getChildren(), listFiles(files[c])); + current[c] = entry; + c++; + } else { + checkAndNotify(entry, entry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + doDelete(entry); + } + } + for (; c < files.length; c++) { + current[c] = createFileEntry(parent, files[c]); + doCreate(current[c]); + } + parent.setChildren(current); + } + + /** + * Create a new file entry for the specified file. + * + * @param parent The parent file entry + * @param file The file to create an entry for + * @return A new file entry + */ + private FileEntry createFileEntry(final FileEntry parent, final File file) { + final FileEntry entry = parent.newChildInstance(file); + entry.refresh(file); + final FileEntry[] children = doListFiles(file, entry); + entry.setChildren(children); + return entry; + } + + /** + * List the files + * + * @param file The file to list files for + * @param entry the parent entry + * @return The child files + */ + private FileEntry[] doListFiles(File file, FileEntry entry) { + final File[] files = listFiles(file); + final FileEntry[] children = files.length > 0 ? new FileEntry[files.length] : EMPTY_ENTRIES; + for (int i = 0; i < files.length; i++) { + children[i] = createFileEntry(entry, files[i]); + } + return children; + } + + /** + * Fire directory/file created events to the registered listeners. + * + * @param entry The file entry + */ + private void doCreate(final FileEntry entry) { + for (final FileAlterationListener listener : listeners) { + if (entry.isDirectory()) { + listener.onDirectoryCreate(entry.getFile()); + } else { + listener.onFileCreate(entry.getFile()); + } + } + final FileEntry[] children = entry.getChildren(); + for (final FileEntry aChildren : children) { + doCreate(aChildren); + } + } + + /** + * Fire directory/file change events to the registered listeners. + * + * @param entry The previous file system entry + * @param file The current file + */ + private void doMatch(final FileEntry entry, final File file) { + if (entry.refresh(file)) { + for (final FileAlterationListener listener : listeners) { + if (entry.isDirectory()) { + listener.onDirectoryChange(file); + } else { + listener.onFileChange(file); + } + } + } + } + + /** + * Fire directory/file delete events to the registered listeners. + * + * @param entry The file entry + */ + private void doDelete(final FileEntry entry) { + for (final FileAlterationListener listener : listeners) { + if (entry.isDirectory()) { + listener.onDirectoryDelete(entry.getFile()); + } else { + listener.onFileDelete(entry.getFile()); + } + } + } + + /** + * List the contents of a directory + * + * @param file The file to list the contents of + * @return the directory contents or a zero length array if + * the empty or the file is not a directory + */ + private File[] listFiles(final File file) { + File[] children = null; + if (file.isDirectory()) { + children = fileFilter == null ? file.listFiles() : file.listFiles(fileFilter); + } + if (children == null) { + children = FileUtils.EMPTY_FILE_ARRAY; + } + if (comparator != null && children.length > 1) { + Arrays.sort(children, comparator); + } + return children; + } + + /** + * Provide a String representation of this observer. + * + * @return a String representation of this observer + */ + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append("[file='"); + builder.append(getDirectory().getPath()); + builder.append('\''); + if (fileFilter != null) { + builder.append(", "); + builder.append(fileFilter.toString()); + } + builder.append(", listeners="); + builder.append(listeners.size()); + builder.append("]"); + return builder.toString(); + } + +} \ No newline at end of file diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 29007746f469..acda0f7aa346 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -45,7 +45,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; @@ -73,7 +72,6 @@ public boolean accept(File pathname) { } }; - FileEntry rootEntry; FileOutputStream fos = null; ArrayList> pairArrayList = new ArrayList<>(); @@ -82,19 +80,13 @@ public boolean accept(File pathname) { for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - FileAlterationObserver observer = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); - Field f; + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( + syncedFolder.getLocalPath()), fileFilter); + try { - observer.initialize(); - f = observer.getClass().getDeclaredField("rootEntry"); - f.setAccessible(true); - rootEntry = (FileEntry) f.get(observer); - Pair pair = new Pair<>(syncedFolder, rootEntry); + observer.init(); + Pair pair = new Pair<>(syncedFolder, observer.getRootEntry()); pairArrayList.add(pair); - } catch (NoSuchFieldException e) { - Log_OC.d(TAG, "Failed getting private field rootEntry via NoSuchFieldException"); - } catch (IllegalAccessException e) { - Log_OC.d(TAG, "Failed getting private field rootEntry via IllegalAccessException"); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); } @@ -120,7 +112,6 @@ public boolean accept(File pathname) { } - try { monitor.start(); } catch (Exception e) { From 2c92eafdda63deae83edf9d176d1daf7361d1f34 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 10:19:55 +0100 Subject: [PATCH 014/138] Add persistence layer on service start --- AndroidManifest.xml | 1 + res/xml/my_backup_rules.xml | 4 + .../observer/SyncedFolderObserverService.java | 92 +++++++++++++++---- 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 res/xml/my_backup_rules.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e8c1a2842147..a90f279b82b5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -59,6 +59,7 @@ + + + diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index acda0f7aa346..0cb94bade725 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -35,15 +35,18 @@ import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.FileAlterationMagicListener; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; import org.apache.commons.io.monitor.FileEntry; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; @@ -72,39 +75,88 @@ public boolean accept(File pathname) { } }; + File file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + "/nc_persistence"); FileOutputStream fos = null; + boolean readPerstistanceEntries = false; ArrayList> pairArrayList = new ArrayList<>(); - Log_OC.d(TAG, "start"); - for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { - if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { - Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( - syncedFolder.getLocalPath()), fileFilter); - + if (file.exists() ) { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + ObjectInputStream ois = new ObjectInputStream(fis); + pairArrayList = (ArrayList>)ois.readObject(); + readPerstistanceEntries = true; + } catch (FileNotFoundException e) { + Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); + } catch (IOException e) { + Log_OC.d(TAG, "Failed with IOException while reading persistence file"); + } catch (ClassNotFoundException e) { + Log_OC.d(TAG, "Failed with ClassNotFound while reading persistence file"); + } finally { try { - observer.init(); - Pair pair = new Pair<>(syncedFolder, observer.getRootEntry()); - pairArrayList.add(pair); - } catch (Exception e) { - Log_OC.d(TAG, "Failed getting an observer to intialize"); + if (fis != null) { + fis.close(); + } + } catch (IOException e) { + Log_OC.d(TAG, "Failed with closing FIS"); + } + } + + } + + Log_OC.d(TAG, "start"); + if (pairArrayList.size() == 0) { + for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { + if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { + Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( + syncedFolder.getLocalPath()), fileFilter); + + try { + observer.init(); + Pair pair = new Pair<>(syncedFolder, observer.getRootEntry()); + pairArrayList.add(pair); + } catch (Exception e) { + Log_OC.d(TAG, "Failed getting an observer to intialize"); + } + + observer.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(observer); + syncedFolderMap.put(syncedFolder.getLocalPath(), observer); } + } + } else { + for(int i = 0; i < pairArrayList.size(); i++) { + SyncedFolder syncFolder = pairArrayList.get(i).first; + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( + syncFolder.getLocalPath()), fileFilter); + observer.setRootEntry(pairArrayList.get(i).second); - observer.addListener(new FileAlterationMagicListener(syncedFolder)); + observer.addListener(new FileAlterationMagicListener(syncFolder)); monitor.addObserver(observer); - syncedFolderMap.put(syncedFolder.getLocalPath(), observer); + syncedFolderMap.put(syncFolder.getLocalPath(), observer); + } } try { - fos = MainApp.getAppContext().openFileOutput("nc_sync_persistance.persist", Context.MODE_PRIVATE); - ObjectOutputStream os = new ObjectOutputStream(fos); - for (int i = 0; i < pairArrayList.size(); i++) { - os.writeObject(pairArrayList.get(i)); + if (pairArrayList.size() > 0 && !readPerstistanceEntries) { + fos = MainApp.getAppContext().openFileOutput(file.getAbsolutePath(), Context.MODE_PRIVATE); + ObjectOutputStream os = new ObjectOutputStream(fos); + for (int i = 0; i < pairArrayList.size(); i++) { + os.writeObject(pairArrayList.get(i)); + } + os.close(); + } else if (file.exists() && pairArrayList.size() == 0) { + FileUtils.deleteQuietly(file); + } + + if (fos != null) { + fos.close(); } - os.close(); - fos.close(); + } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); } catch (IOException e) { From 0b9187d32cf33cc30979744656d611182a0d7d7e Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 22:01:45 +0100 Subject: [PATCH 015/138] Progress on implementing persistance --- .../observer/SyncedFolderObserverService.java | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 0cb94bade725..f322c89d7988 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -37,7 +37,6 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationMonitor; -import org.apache.commons.io.monitor.FileAlterationObserver; import org.apache.commons.io.monitor.FileEntry; import java.io.File; @@ -54,10 +53,12 @@ public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; private SyncedFolderProvider mProvider; - private HashMap syncedFolderMap = new HashMap<>(); + private HashMap syncedFolderMap = new HashMap<>(); private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; + private ArrayList> pairArrayList = new ArrayList<>(); + private File file; @Override public void onCreate() { @@ -75,11 +76,9 @@ public boolean accept(File pathname) { } }; - File file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + "/nc_persistence"); + file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + "/nc_persistence"); - FileOutputStream fos = null; boolean readPerstistanceEntries = false; - ArrayList> pairArrayList = new ArrayList<>(); if (file.exists() ) { FileInputStream fis = null; @@ -124,7 +123,7 @@ public boolean accept(File pathname) { observer.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(observer); - syncedFolderMap.put(syncedFolder.getLocalPath(), observer); + syncedFolderMap.put(syncedFolder, observer); } } } else { @@ -136,11 +135,26 @@ public boolean accept(File pathname) { observer.addListener(new FileAlterationMagicListener(syncFolder)); monitor.addObserver(observer); - syncedFolderMap.put(syncFolder.getLocalPath(), observer); + syncedFolderMap.put(syncFolder, observer); } } + writePersistenceEntries(readPerstistanceEntries, file); + + try { + monitor.start(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onStartCommand"); + } + + + return Service.START_NOT_STICKY; + } + + private void writePersistenceEntries(boolean readPerstistanceEntries, File file) { + FileOutputStream fos = null; + try { if (pairArrayList.size() > 0 && !readPerstistanceEntries) { fos = MainApp.getAppContext().openFileOutput(file.getAbsolutePath(), Context.MODE_PRIVATE); @@ -162,29 +176,32 @@ public boolean accept(File pathname) { } catch (IOException e) { Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via IOException"); } - - - try { - monitor.start(); - } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong at onStartCommand"); - } - - - return Service.START_NOT_STICKY; } @Override public void onDestroy() { - for (FileAlterationObserver observer : syncedFolderMap.values()) { - monitor.removeObserver(observer); + + for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { + FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); + for (int i = 0; i < pairArrayList.size(); i++) { + SyncedFolder pairSyncedFolder = pairArrayList.get(i).first; + if (pairSyncedFolder.equals(syncedFolder)) { + Pair newPairEntry = new Pair<>(syncedFolder, obs.getRootEntry()); + pairArrayList.set(i, newPairEntry); + break; + } + } + monitor.removeObserver(obs); + syncedFolderMap.remove(obs); + try { - observer.destroy(); + obs.destroy(); } catch (Exception e) { Log_OC.d(TAG, "Something went very wrong at onDestroy"); } - syncedFolderMap.remove(observer); } + + writePersistenceEntries(false, file); } /** @@ -195,33 +212,34 @@ public void onDestroy() { */ public void restartObserver(SyncedFolder syncedFolder) { - FileAlterationObserver fileAlterationObserver; - if (syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { + FileAlterationMagicObserver fileAlterationObserver; + if (syncedFolderMap.containsKey(syncedFolder)) { Log_OC.d(TAG, "stop observer: " + syncedFolder.getLocalPath()); - fileAlterationObserver = syncedFolderMap.get(syncedFolder.getLocalPath()); + fileAlterationObserver = syncedFolderMap.get(syncedFolder); monitor.removeObserver(fileAlterationObserver); try { fileAlterationObserver.destroy(); } catch (Exception e) { Log_OC.d(TAG, "Something went very wrong at onDestroy"); } - syncedFolderMap.remove(syncedFolder.getLocalPath()); + syncedFolderMap.remove(syncedFolder); } if (syncedFolder.isEnabled()) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - if (syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { - fileAlterationObserver = syncedFolderMap.get(syncedFolder.getLocalPath()); + if (syncedFolderMap.containsKey(syncedFolder)) { + fileAlterationObserver = syncedFolderMap.get(syncedFolder); if (fileAlterationObserver.getListeners() == null) { fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); } monitor.addObserver(fileAlterationObserver); } else { - fileAlterationObserver = new FileAlterationObserver(syncedFolder.getLocalPath(), fileFilter); + fileAlterationObserver = new FileAlterationMagicObserver(new File(syncedFolder.getLocalPath()), + fileFilter); fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(fileAlterationObserver); try { - syncedFolderMap.put(syncedFolder.getLocalPath(), fileAlterationObserver); + syncedFolderMap.put(syncedFolder, fileAlterationObserver); } catch (Exception e) { Log_OC.d(TAG, "Something went very wrong on RestartObserver"); } From 37f31c51725c629fd44beeccba7b4b0eb24ecbc1 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 22:02:24 +0100 Subject: [PATCH 016/138] Fix a typo with tmp files --- .../android/services/observer/SyncedFolderObserverService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index f322c89d7988..e843672e255e 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -72,7 +72,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { - return !pathname.getName().startsWith(".") && !pathname.getAbsolutePath().endsWith(".tmp"); + return !pathname.getName().startsWith(".") && !pathname.getName().endsWith(".tmp"); } }; From 6aba87ef97ce493463a5256c1a1b5e52c2aa4903 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 22:52:50 +0100 Subject: [PATCH 017/138] Magical magical stuff --- .../observer/SyncedFolderObserverService.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index e843672e255e..c06744980669 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -47,8 +47,8 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.CopyOnWriteArrayList; public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; @@ -57,7 +57,7 @@ public class SyncedFolderObserverService extends Service { private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; - private ArrayList> pairArrayList = new ArrayList<>(); + private CopyOnWriteArrayList> pairArrayList = new CopyOnWriteArrayList<>(); private File file; @Override @@ -85,7 +85,7 @@ public boolean accept(File pathname) { try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); - pairArrayList = (ArrayList>)ois.readObject(); + pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); @@ -222,6 +222,14 @@ public void restartObserver(SyncedFolder syncedFolder) { } catch (Exception e) { Log_OC.d(TAG, "Something went very wrong at onDestroy"); } + + // remove it from the paired array list + for (int i = 0; i < pairArrayList.size(); i++) { + if (syncedFolder.equals(pairArrayList.get(i).first)) { + pairArrayList.remove(i); + break; + } + } syncedFolderMap.remove(syncedFolder); } @@ -236,6 +244,15 @@ public void restartObserver(SyncedFolder syncedFolder) { } else { fileAlterationObserver = new FileAlterationMagicObserver(new File(syncedFolder.getLocalPath()), fileFilter); + + try { + fileAlterationObserver.init(); + Pair pair = new Pair<>(syncedFolder, fileAlterationObserver.getRootEntry()); + pairArrayList.add(pair); + } catch (Exception e) { + Log_OC.d(TAG, "Failed getting an observer to intialize"); + } + fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(fileAlterationObserver); try { @@ -246,6 +263,8 @@ public void restartObserver(SyncedFolder syncedFolder) { } } + + writePersistenceEntries(false, file); } @Override From fe4c44a586857721e00978cfb5e383fed65b9214 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 22:56:51 +0100 Subject: [PATCH 018/138] Remove useless conditions --- .../observer/SyncedFolderObserverService.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index c06744980669..30c5fb1095b3 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -78,7 +78,6 @@ public boolean accept(File pathname) { file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + "/nc_persistence"); - boolean readPerstistanceEntries = false; if (file.exists() ) { FileInputStream fis = null; @@ -86,7 +85,6 @@ public boolean accept(File pathname) { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); - readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); } catch (IOException e) { @@ -140,7 +138,7 @@ public boolean accept(File pathname) { } } - writePersistenceEntries(readPerstistanceEntries, file); + writePersistenceEntries(file); try { monitor.start(); @@ -152,11 +150,11 @@ public boolean accept(File pathname) { return Service.START_NOT_STICKY; } - private void writePersistenceEntries(boolean readPerstistanceEntries, File file) { + private void writePersistenceEntries(File file) { FileOutputStream fos = null; try { - if (pairArrayList.size() > 0 && !readPerstistanceEntries) { + if (pairArrayList.size() > 0) { fos = MainApp.getAppContext().openFileOutput(file.getAbsolutePath(), Context.MODE_PRIVATE); ObjectOutputStream os = new ObjectOutputStream(fos); for (int i = 0; i < pairArrayList.size(); i++) { @@ -201,7 +199,7 @@ public void onDestroy() { } } - writePersistenceEntries(false, file); + writePersistenceEntries(file); } /** @@ -264,7 +262,7 @@ public void restartObserver(SyncedFolder syncedFolder) { } } - writePersistenceEntries(false, file); + writePersistenceEntries(file); } @Override From f5f115e7904a7dfb80ecd75933c7b5427c7a9e9f Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 22:59:09 +0100 Subject: [PATCH 019/138] Revert "Remove useless conditions" This reverts commit 5dd6d9181eaa36f5177760046d71dade444698ad. --- .../observer/SyncedFolderObserverService.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 30c5fb1095b3..c06744980669 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -78,6 +78,7 @@ public boolean accept(File pathname) { file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + "/nc_persistence"); + boolean readPerstistanceEntries = false; if (file.exists() ) { FileInputStream fis = null; @@ -85,6 +86,7 @@ public boolean accept(File pathname) { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); + readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); } catch (IOException e) { @@ -138,7 +140,7 @@ public boolean accept(File pathname) { } } - writePersistenceEntries(file); + writePersistenceEntries(readPerstistanceEntries, file); try { monitor.start(); @@ -150,11 +152,11 @@ public boolean accept(File pathname) { return Service.START_NOT_STICKY; } - private void writePersistenceEntries(File file) { + private void writePersistenceEntries(boolean readPerstistanceEntries, File file) { FileOutputStream fos = null; try { - if (pairArrayList.size() > 0) { + if (pairArrayList.size() > 0 && !readPerstistanceEntries) { fos = MainApp.getAppContext().openFileOutput(file.getAbsolutePath(), Context.MODE_PRIVATE); ObjectOutputStream os = new ObjectOutputStream(fos); for (int i = 0; i < pairArrayList.size(); i++) { @@ -199,7 +201,7 @@ public void onDestroy() { } } - writePersistenceEntries(file); + writePersistenceEntries(false, file); } /** @@ -262,7 +264,7 @@ public void restartObserver(SyncedFolder syncedFolder) { } } - writePersistenceEntries(file); + writePersistenceEntries(false, file); } @Override From c94f78254b7226474d7df4c922e871d2a2aa48bc Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 23:13:55 +0100 Subject: [PATCH 020/138] Fix a bug --- .../services/observer/SyncedFolderObserverService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index c06744980669..245a96a65998 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -23,7 +23,6 @@ package com.owncloud.android.services.observer; import android.app.Service; -import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; @@ -76,7 +75,8 @@ public boolean accept(File pathname) { } }; - file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + "/nc_persistence"); + file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + File.separator + + "nc_persistence"); boolean readPerstistanceEntries = false; @@ -157,7 +157,7 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) try { if (pairArrayList.size() > 0 && !readPerstistanceEntries) { - fos = MainApp.getAppContext().openFileOutput(file.getAbsolutePath(), Context.MODE_PRIVATE); + fos = new FileOutputStream (new File(file.getAbsolutePath()), false); ObjectOutputStream os = new ObjectOutputStream(fos); for (int i = 0; i < pairArrayList.size(); i++) { os.writeObject(pairArrayList.get(i)); From eeb72d1be0bbc2f872333595b8b00876beb2aa3d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 23:15:36 +0100 Subject: [PATCH 021/138] Create new file --- .../services/observer/SyncedFolderObserverService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 245a96a65998..eab001e205c5 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -157,6 +157,10 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) try { if (pairArrayList.size() > 0 && !readPerstistanceEntries) { + File newFile = new File(file.getAbsolutePath()); + if (!newFile.exists()) { + newFile.createNewFile(); + } fos = new FileOutputStream (new File(file.getAbsolutePath()), false); ObjectOutputStream os = new ObjectOutputStream(fos); for (int i = 0; i < pairArrayList.size(); i++) { From 5dcdcaffd2c21dff9ae51ba02733b8f944892380 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 5 Feb 2017 23:54:03 +0100 Subject: [PATCH 022/138] Fix a serialization bug --- .../android/datamodel/SerializablePair.java | 51 +++++++++++++++++++ .../observer/SyncedFolderObserverService.java | 30 ++++++----- 2 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 src/com/owncloud/android/datamodel/SerializablePair.java diff --git a/src/com/owncloud/android/datamodel/SerializablePair.java b/src/com/owncloud/android/datamodel/SerializablePair.java new file mode 100644 index 000000000000..8df9b4c98587 --- /dev/null +++ b/src/com/owncloud/android/datamodel/SerializablePair.java @@ -0,0 +1,51 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.datamodel; + +import android.support.v4.util.Pair; + +import org.apache.commons.io.monitor.FileEntry; + +import java.io.Serializable; + +/** + * Pair that we can serialize + */ + +public class SerializablePair implements Serializable { + private transient Pair pair = null; + + public SerializablePair(SyncedFolder key, FileEntry value) { + this.pair = new Pair(key, value); + } + + @Override + public String toString() { + return pair.toString(); + } + + public SyncedFolder getKey() { + return (SyncedFolder)this.pair.first; + } + + public FileEntry getValue() { + return (FileEntry)this.pair.second; + } +} diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index eab001e205c5..45d536444aef 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -6,17 +6,17 @@ * @author Mario Danic * Copyright (C) 2016 Tobias Kaminsky, Andy Scherzinger * Copyright (C) 2017 Mario Danic - *

+ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. - *

+ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - *

+ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -26,9 +26,9 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import android.support.v4.util.Pair; import com.owncloud.android.MainApp; +import com.owncloud.android.datamodel.SerializablePair; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; @@ -56,7 +56,7 @@ public class SyncedFolderObserverService extends Service { private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; - private CopyOnWriteArrayList> pairArrayList = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList> pairArrayList = new CopyOnWriteArrayList<>(); private File file; @Override @@ -85,7 +85,7 @@ public boolean accept(File pathname) { try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); - pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); + pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); @@ -115,7 +115,8 @@ public boolean accept(File pathname) { try { observer.init(); - Pair pair = new Pair<>(syncedFolder, observer.getRootEntry()); + SerializablePair pair = new SerializablePair<>(syncedFolder, + observer.getRootEntry()); pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); @@ -128,10 +129,10 @@ public boolean accept(File pathname) { } } else { for(int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder syncFolder = pairArrayList.get(i).first; + SyncedFolder syncFolder = pairArrayList.get(i).getKey(); FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( syncFolder.getLocalPath()), fileFilter); - observer.setRootEntry(pairArrayList.get(i).second); + observer.setRootEntry(pairArrayList.get(i).getValue()); observer.addListener(new FileAlterationMagicListener(syncFolder)); monitor.addObserver(observer); @@ -180,6 +181,7 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) } catch (IOException e) { Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via IOException"); } + } @Override @@ -188,9 +190,10 @@ public void onDestroy() { for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); for (int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder pairSyncedFolder = pairArrayList.get(i).first; + SyncedFolder pairSyncedFolder = pairArrayList.get(i).getKey(); if (pairSyncedFolder.equals(syncedFolder)) { - Pair newPairEntry = new Pair<>(syncedFolder, obs.getRootEntry()); + SerializablePair newPairEntry = new SerializablePair<>(syncedFolder, + obs.getRootEntry()); pairArrayList.set(i, newPairEntry); break; } @@ -229,7 +232,7 @@ public void restartObserver(SyncedFolder syncedFolder) { // remove it from the paired array list for (int i = 0; i < pairArrayList.size(); i++) { - if (syncedFolder.equals(pairArrayList.get(i).first)) { + if (syncedFolder.equals(pairArrayList.get(i).getKey())) { pairArrayList.remove(i); break; } @@ -251,7 +254,8 @@ public void restartObserver(SyncedFolder syncedFolder) { try { fileAlterationObserver.init(); - Pair pair = new Pair<>(syncedFolder, fileAlterationObserver.getRootEntry()); + SerializablePair pair = new SerializablePair<>(syncedFolder, + fileAlterationObserver.getRootEntry()); pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); From c1f896a07a849ebc3f65f01e449ecdf9940502d5 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 01:25:04 +0100 Subject: [PATCH 023/138] Use different models --- .../{SerializablePair.java => RealPair.java} | 41 +++++++++++------ .../observer/SyncedFolderObserverService.java | 45 +++++++++---------- 2 files changed, 49 insertions(+), 37 deletions(-) rename src/com/owncloud/android/datamodel/{SerializablePair.java => RealPair.java} (54%) diff --git a/src/com/owncloud/android/datamodel/SerializablePair.java b/src/com/owncloud/android/datamodel/RealPair.java similarity index 54% rename from src/com/owncloud/android/datamodel/SerializablePair.java rename to src/com/owncloud/android/datamodel/RealPair.java index 8df9b4c98587..b5d248aa01c6 100644 --- a/src/com/owncloud/android/datamodel/SerializablePair.java +++ b/src/com/owncloud/android/datamodel/RealPair.java @@ -19,8 +19,6 @@ */ package com.owncloud.android.datamodel; -import android.support.v4.util.Pair; - import org.apache.commons.io.monitor.FileEntry; import java.io.Serializable; @@ -29,23 +27,40 @@ * Pair that we can serialize */ -public class SerializablePair implements Serializable { - private transient Pair pair = null; +public class RealPair implements Serializable { + private static final long serialVersionUID = 3823582869520000090L; + + private SyncedFolder syncedFolder; + private FileEntry fileEntry; + + public RealPair() { + + } + + public RealPair(SyncedFolder syncedFolder, FileEntry fileEntry) { - public SerializablePair(SyncedFolder key, FileEntry value) { - this.pair = new Pair(key, value); + this.syncedFolder = syncedFolder; + this.fileEntry = fileEntry; } - @Override - public String toString() { - return pair.toString(); + public static long getSerialVersionUID() { + return serialVersionUID; } - public SyncedFolder getKey() { - return (SyncedFolder)this.pair.first; + public SyncedFolder getSyncedFolder() { + return syncedFolder; } - public FileEntry getValue() { - return (FileEntry)this.pair.second; + public void setSyncedFolder(SyncedFolder syncedFolder) { + this.syncedFolder = syncedFolder; } + + public FileEntry getFileEntry() { + return fileEntry; + } + + public void setFileEntry(FileEntry fileEntry) { + this.fileEntry = fileEntry; + } + } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 45d536444aef..10cc07f6eda0 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -28,7 +28,7 @@ import android.os.IBinder; import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.SerializablePair; +import com.owncloud.android.datamodel.RealPair; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; @@ -36,7 +36,6 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationMonitor; -import org.apache.commons.io.monitor.FileEntry; import java.io.File; import java.io.FileFilter; @@ -56,7 +55,7 @@ public class SyncedFolderObserverService extends Service { private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; - private CopyOnWriteArrayList> pairArrayList = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList pairArrayList = new CopyOnWriteArrayList<>(); private File file; @Override @@ -85,7 +84,7 @@ public boolean accept(File pathname) { try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); - pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); + pairArrayList = (CopyOnWriteArrayList)ois.readObject(); readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); @@ -115,8 +114,7 @@ public boolean accept(File pathname) { try { observer.init(); - SerializablePair pair = new SerializablePair<>(syncedFolder, - observer.getRootEntry()); + RealPair pair = new RealPair(syncedFolder, observer.getRootEntry()); pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); @@ -129,10 +127,10 @@ public boolean accept(File pathname) { } } else { for(int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder syncFolder = pairArrayList.get(i).getKey(); + SyncedFolder syncFolder = pairArrayList.get(i).getSyncedFolder(); FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( syncFolder.getLocalPath()), fileFilter); - observer.setRootEntry(pairArrayList.get(i).getValue()); + observer.setRootEntry(pairArrayList.get(i).getFileEntry()); observer.addListener(new FileAlterationMagicListener(syncFolder)); monitor.addObserver(observer); @@ -155,19 +153,15 @@ public boolean accept(File pathname) { private void writePersistenceEntries(boolean readPerstistanceEntries, File file) { FileOutputStream fos = null; - + ObjectOutputStream os = null; try { if (pairArrayList.size() > 0 && !readPerstistanceEntries) { - File newFile = new File(file.getAbsolutePath()); - if (!newFile.exists()) { - newFile.createNewFile(); - } - fos = new FileOutputStream (new File(file.getAbsolutePath()), false); - ObjectOutputStream os = new ObjectOutputStream(fos); - for (int i = 0; i < pairArrayList.size(); i++) { - os.writeObject(pairArrayList.get(i)); + if (!file.exists()) { + file.createNewFile(); } - os.close(); + fos = FileUtils.openOutputStream(file, false); + os = new ObjectOutputStream(fos); + os.writeObject(pairArrayList); } else if (file.exists() && pairArrayList.size() == 0) { FileUtils.deleteQuietly(file); } @@ -176,6 +170,11 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) fos.close(); } + if (os != null) { + os.close(); + } + + } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); } catch (IOException e) { @@ -190,10 +189,9 @@ public void onDestroy() { for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); for (int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder pairSyncedFolder = pairArrayList.get(i).getKey(); + SyncedFolder pairSyncedFolder = pairArrayList.get(i).getSyncedFolder(); if (pairSyncedFolder.equals(syncedFolder)) { - SerializablePair newPairEntry = new SerializablePair<>(syncedFolder, - obs.getRootEntry()); + RealPair newPairEntry = new RealPair(syncedFolder, obs.getRootEntry()); pairArrayList.set(i, newPairEntry); break; } @@ -232,7 +230,7 @@ public void restartObserver(SyncedFolder syncedFolder) { // remove it from the paired array list for (int i = 0; i < pairArrayList.size(); i++) { - if (syncedFolder.equals(pairArrayList.get(i).getKey())) { + if (syncedFolder.equals(pairArrayList.get(i).getSyncedFolder())) { pairArrayList.remove(i); break; } @@ -254,8 +252,7 @@ public void restartObserver(SyncedFolder syncedFolder) { try { fileAlterationObserver.init(); - SerializablePair pair = new SerializablePair<>(syncedFolder, - fileAlterationObserver.getRootEntry()); + RealPair pair = new RealPair(syncedFolder, fileAlterationObserver.getRootEntry()); pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); From deb35e5b9ff507a4226d121ac293609ed4e5911c Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 01:30:19 +0100 Subject: [PATCH 024/138] Revert "Use different models" This reverts commit ab901a6b954d8ba8800a0371c2b5e7c36fe0dbf7. --- .../{RealPair.java => SerializablePair.java} | 41 ++++++----------- .../observer/SyncedFolderObserverService.java | 45 ++++++++++--------- 2 files changed, 37 insertions(+), 49 deletions(-) rename src/com/owncloud/android/datamodel/{RealPair.java => SerializablePair.java} (54%) diff --git a/src/com/owncloud/android/datamodel/RealPair.java b/src/com/owncloud/android/datamodel/SerializablePair.java similarity index 54% rename from src/com/owncloud/android/datamodel/RealPair.java rename to src/com/owncloud/android/datamodel/SerializablePair.java index b5d248aa01c6..8df9b4c98587 100644 --- a/src/com/owncloud/android/datamodel/RealPair.java +++ b/src/com/owncloud/android/datamodel/SerializablePair.java @@ -19,6 +19,8 @@ */ package com.owncloud.android.datamodel; +import android.support.v4.util.Pair; + import org.apache.commons.io.monitor.FileEntry; import java.io.Serializable; @@ -27,40 +29,23 @@ * Pair that we can serialize */ -public class RealPair implements Serializable { - private static final long serialVersionUID = 3823582869520000090L; - - private SyncedFolder syncedFolder; - private FileEntry fileEntry; - - public RealPair() { - - } - - public RealPair(SyncedFolder syncedFolder, FileEntry fileEntry) { +public class SerializablePair implements Serializable { + private transient Pair pair = null; - this.syncedFolder = syncedFolder; - this.fileEntry = fileEntry; + public SerializablePair(SyncedFolder key, FileEntry value) { + this.pair = new Pair(key, value); } - public static long getSerialVersionUID() { - return serialVersionUID; + @Override + public String toString() { + return pair.toString(); } - public SyncedFolder getSyncedFolder() { - return syncedFolder; + public SyncedFolder getKey() { + return (SyncedFolder)this.pair.first; } - public void setSyncedFolder(SyncedFolder syncedFolder) { - this.syncedFolder = syncedFolder; + public FileEntry getValue() { + return (FileEntry)this.pair.second; } - - public FileEntry getFileEntry() { - return fileEntry; - } - - public void setFileEntry(FileEntry fileEntry) { - this.fileEntry = fileEntry; - } - } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 10cc07f6eda0..45d536444aef 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -28,7 +28,7 @@ import android.os.IBinder; import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.RealPair; +import com.owncloud.android.datamodel.SerializablePair; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; @@ -36,6 +36,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationMonitor; +import org.apache.commons.io.monitor.FileEntry; import java.io.File; import java.io.FileFilter; @@ -55,7 +56,7 @@ public class SyncedFolderObserverService extends Service { private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; - private CopyOnWriteArrayList pairArrayList = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList> pairArrayList = new CopyOnWriteArrayList<>(); private File file; @Override @@ -84,7 +85,7 @@ public boolean accept(File pathname) { try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); - pairArrayList = (CopyOnWriteArrayList)ois.readObject(); + pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); @@ -114,7 +115,8 @@ public boolean accept(File pathname) { try { observer.init(); - RealPair pair = new RealPair(syncedFolder, observer.getRootEntry()); + SerializablePair pair = new SerializablePair<>(syncedFolder, + observer.getRootEntry()); pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); @@ -127,10 +129,10 @@ public boolean accept(File pathname) { } } else { for(int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder syncFolder = pairArrayList.get(i).getSyncedFolder(); + SyncedFolder syncFolder = pairArrayList.get(i).getKey(); FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( syncFolder.getLocalPath()), fileFilter); - observer.setRootEntry(pairArrayList.get(i).getFileEntry()); + observer.setRootEntry(pairArrayList.get(i).getValue()); observer.addListener(new FileAlterationMagicListener(syncFolder)); monitor.addObserver(observer); @@ -153,15 +155,19 @@ public boolean accept(File pathname) { private void writePersistenceEntries(boolean readPerstistanceEntries, File file) { FileOutputStream fos = null; - ObjectOutputStream os = null; + try { if (pairArrayList.size() > 0 && !readPerstistanceEntries) { - if (!file.exists()) { - file.createNewFile(); + File newFile = new File(file.getAbsolutePath()); + if (!newFile.exists()) { + newFile.createNewFile(); + } + fos = new FileOutputStream (new File(file.getAbsolutePath()), false); + ObjectOutputStream os = new ObjectOutputStream(fos); + for (int i = 0; i < pairArrayList.size(); i++) { + os.writeObject(pairArrayList.get(i)); } - fos = FileUtils.openOutputStream(file, false); - os = new ObjectOutputStream(fos); - os.writeObject(pairArrayList); + os.close(); } else if (file.exists() && pairArrayList.size() == 0) { FileUtils.deleteQuietly(file); } @@ -170,11 +176,6 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) fos.close(); } - if (os != null) { - os.close(); - } - - } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); } catch (IOException e) { @@ -189,9 +190,10 @@ public void onDestroy() { for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); for (int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder pairSyncedFolder = pairArrayList.get(i).getSyncedFolder(); + SyncedFolder pairSyncedFolder = pairArrayList.get(i).getKey(); if (pairSyncedFolder.equals(syncedFolder)) { - RealPair newPairEntry = new RealPair(syncedFolder, obs.getRootEntry()); + SerializablePair newPairEntry = new SerializablePair<>(syncedFolder, + obs.getRootEntry()); pairArrayList.set(i, newPairEntry); break; } @@ -230,7 +232,7 @@ public void restartObserver(SyncedFolder syncedFolder) { // remove it from the paired array list for (int i = 0; i < pairArrayList.size(); i++) { - if (syncedFolder.equals(pairArrayList.get(i).getSyncedFolder())) { + if (syncedFolder.equals(pairArrayList.get(i).getKey())) { pairArrayList.remove(i); break; } @@ -252,7 +254,8 @@ public void restartObserver(SyncedFolder syncedFolder) { try { fileAlterationObserver.init(); - RealPair pair = new RealPair(syncedFolder, fileAlterationObserver.getRootEntry()); + SerializablePair pair = new SerializablePair<>(syncedFolder, + fileAlterationObserver.getRootEntry()); pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); From e996a3dcc99f2d0eaf1dc112fd0219a6ab435f09 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 01:46:08 +0100 Subject: [PATCH 025/138] Fix persistance --- .../android/datamodel/SerializablePair.java | 15 +++++++++++++++ .../owncloud/android/datamodel/SyncedFolder.java | 5 ++++- .../observer/SyncedFolderObserverService.java | 11 ++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/datamodel/SerializablePair.java b/src/com/owncloud/android/datamodel/SerializablePair.java index 8df9b4c98587..4746b1dacfa3 100644 --- a/src/com/owncloud/android/datamodel/SerializablePair.java +++ b/src/com/owncloud/android/datamodel/SerializablePair.java @@ -23,6 +23,7 @@ import org.apache.commons.io.monitor.FileEntry; +import java.io.IOException; import java.io.Serializable; /** @@ -30,12 +31,26 @@ */ public class SerializablePair implements Serializable { + private static final long serialVersionUID = -1710182118966395715L; private transient Pair pair = null; public SerializablePair(SyncedFolder key, FileEntry value) { this.pair = new Pair(key, value); } + private void writeObject(java.io.ObjectOutputStream stream) + throws IOException { + stream.writeObject(pair.first); + stream.writeObject(pair.second); + } + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + SyncedFolder syncedFolder = (SyncedFolder) stream.readObject(); + FileEntry fileEntry = (FileEntry) stream.readObject(); + pair = new Pair(syncedFolder, fileEntry); + } + @Override public String toString() { return pair.toString(); diff --git a/src/com/owncloud/android/datamodel/SyncedFolder.java b/src/com/owncloud/android/datamodel/SyncedFolder.java index a931b1263e40..7a3beb25a9b8 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolder.java +++ b/src/com/owncloud/android/datamodel/SyncedFolder.java @@ -21,11 +21,14 @@ package com.owncloud.android.datamodel; +import java.io.Serializable; + /** * Synced folder entity containing all information per synced folder. */ -public class SyncedFolder { +public class SyncedFolder implements Serializable{ public static final long UNPERSISTED_ID = Long.MIN_VALUE; + private static final long serialVersionUID = -793476118299906429L; private long id = UNPERSISTED_ID; private String localPath; private String remotePath; diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 45d536444aef..2c403c4d2a0a 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -85,7 +85,15 @@ public boolean accept(File pathname) { try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); - pairArrayList = (CopyOnWriteArrayList>)ois.readObject(); + boolean cont = true; + while(cont){ + Object obj = ois.readObject(); + if(obj != null) + pairArrayList.add((SerializablePair) obj); + else + cont = false; + } + readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); @@ -182,6 +190,7 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via IOException"); } + } @Override From 6266be2a3be44e3c518bee3934e9f1892c4389e0 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 01:49:43 +0100 Subject: [PATCH 026/138] Optimize imports --- .../android/services/FileAlterationMagicListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 1b9badbecc82..2336700df1b5 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -3,17 +3,17 @@ * * @author Mario Danic * Copyright (C) 2017 Mario Danic - * + *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + *

* You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ From 3fdd90c545b0e6a6a99f01327360ff5f7a5dbf16 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 02:13:20 +0100 Subject: [PATCH 027/138] Attempt to fix HDR issues --- .../services/FileAlterationMagicListener.java | 83 ++++++++++++------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 2336700df1b5..9351af35a4f9 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -3,17 +3,17 @@ * * @author Mario Danic * Copyright (C) 2017 Mario Danic - *

+ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. - *

+ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - *

+ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,6 +23,7 @@ import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; +import android.os.Handler; import android.os.PersistableBundle; import com.owncloud.android.MainApp; @@ -35,6 +36,8 @@ import java.io.File; import java.util.Date; +import java.util.HashMap; +import java.util.Map; /** * Magical file alteration listener @@ -47,6 +50,9 @@ public class FileAlterationMagicListener implements FileAlterationListener { private Context context; private SyncedFolder syncedFolder; + private Handler handler = new Handler(); + + private Map fileRunnable = new HashMap<>(); public FileAlterationMagicListener(SyncedFolder syncedFolder) { super(); @@ -76,40 +82,53 @@ public void onDirectoryDelete(File directory) { } @Override - public void onFileCreate(File file) { - PersistableBundle bundle = new PersistableBundle(); - // TODO extract - bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); - bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( - syncedFolder.getRemotePath(), file.getName(), - new Date().getTime(), - syncedFolder.getSubfolderByDate())); - bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); - bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); - - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - Long date = new Date().getTime(); - JobInfo job = new JobInfo.Builder( - date.intValue(), - new ComponentName(context, SyncedFolderJobService.class)) - .setRequiresCharging(syncedFolder.getChargingOnly()) - .setMinimumLatency(10000) - .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) - .setExtras(bundle) - .setPersisted(true) - .build(); - - Integer result = js.schedule(job); - if (result <= 0) { - Log_OC.d(TAG, "Job failed to start: " + result); - } + public void onFileCreate(final File file) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + PersistableBundle bundle = new PersistableBundle(); + // TODO extract + bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); + bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( + syncedFolder.getRemotePath(), file.getName(), + new Date().getTime(), + syncedFolder.getSubfolderByDate())); + bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); + bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); + + JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + Long date = new Date().getTime(); + JobInfo job = new JobInfo.Builder( + date.intValue(), + new ComponentName(context, SyncedFolderJobService.class)) + .setRequiresCharging(syncedFolder.getChargingOnly()) + .setMinimumLatency(10000) + .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) + .setExtras(bundle) + .setPersisted(true) + .build(); + + Integer result = js.schedule(job); + if (result <= 0) { + Log_OC.d(TAG, "Job failed to start: " + result); + } + + fileRunnable.remove(file.getAbsolutePath()); + } + }; + + fileRunnable.put(file.getAbsolutePath(), runnable); + handler.postDelayed(runnable, 500); } @Override public void onFileChange(File file) { - // This method is intentionally empty + if (fileRunnable.containsKey(file.getAbsolutePath())) { + handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); + handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 500); + } } @Override From cca154a2e129870ce680d69b0a0c60b60fec913d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 12:43:42 +0100 Subject: [PATCH 028/138] Fix to aid in HDR stuff processing --- .../android/services/FileAlterationMagicListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 9351af35a4f9..ff89a780c87e 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -133,7 +133,9 @@ public void onFileChange(File file) { @Override public void onFileDelete(File file) { - // This method is intentionally empty + if (fileRunnable.containsKey(file.getAbsolutePath())) { + handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); + } } @Override From 0fb06dac69b060b4d7ec1f7f96934458c0764a84 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 13:21:04 +0100 Subject: [PATCH 029/138] Some progress on auto-upload fixes --- .../android/services/FileAlterationMagicListener.java | 2 ++ .../services/observer/SyncedFolderObserverService.java | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index ff89a780c87e..124e193baf63 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -128,6 +128,7 @@ public void onFileChange(File file) { if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 500); + fileRunnable.remove(file.getAbsolutePath()); } } @@ -135,6 +136,7 @@ public void onFileChange(File file) { public void onFileDelete(File file) { if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); + fileRunnable.remove(file.getAbsolutePath()); } } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 2c403c4d2a0a..a496e29f6da2 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -138,6 +138,15 @@ public boolean accept(File pathname) { } else { for(int i = 0; i < pairArrayList.size(); i++) { SyncedFolder syncFolder = pairArrayList.get(i).getKey(); + for(SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { + if (syncFolder.getId() == syncedFolder.getId()) { + syncFolder = syncedFolder; + pairArrayList.set(i, new SerializablePair(syncFolder, + pairArrayList.get(i).getValue())); + break; + } + } + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( syncFolder.getLocalPath()), fileFilter); observer.setRootEntry(pairArrayList.get(i).getValue()); From c8785b76cc21d0d0513fd5fe1657d23ac15a9971 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 17:09:36 +0100 Subject: [PATCH 030/138] Partial revert "Some progress on auto-upload fixes" This reverts commit 9c39a6dfdca7866a3856e857af7c0204ab229af6. --- .../owncloud/android/services/FileAlterationMagicListener.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 124e193baf63..ff89a780c87e 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -128,7 +128,6 @@ public void onFileChange(File file) { if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 500); - fileRunnable.remove(file.getAbsolutePath()); } } @@ -136,7 +135,6 @@ public void onFileChange(File file) { public void onFileDelete(File file) { if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); - fileRunnable.remove(file.getAbsolutePath()); } } From 0c8beeb56c2f13df534e60b5a4f9a5a7a6cdd36d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 20:01:46 +0100 Subject: [PATCH 031/138] Re-arrange things a bit --- .../observer/SyncedFolderObserverService.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index a496e29f6da2..79d06ef7deed 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -38,6 +38,7 @@ import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileEntry; +import java.io.EOFException; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -62,10 +63,6 @@ public class SyncedFolderObserverService extends Service { @Override public void onCreate() { mProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { monitor = new FileAlterationMonitor(); fileFilter = new FileFilter() { @@ -97,6 +94,9 @@ public boolean accept(File pathname) { readPerstistanceEntries = true; } catch (FileNotFoundException e) { Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); + } catch (EOFException e) { + Log_OC.d(TAG, "Failed with EOFException while reading persistence file"); + readPerstistanceEntries = true; } catch (IOException e) { Log_OC.d(TAG, "Failed with IOException while reading persistence file"); } catch (ClassNotFoundException e) { @@ -166,7 +166,10 @@ public boolean accept(File pathname) { Log_OC.d(TAG, "Something went very wrong at onStartCommand"); } + } + @Override + public int onStartCommand(Intent intent, int flags, int startId) { return Service.START_NOT_STICKY; } @@ -204,7 +207,6 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) @Override public void onDestroy() { - for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); for (int i = 0; i < pairArrayList.size(); i++) { From df5076612673d5974a3746c0e807b413e94b9b23 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 23:13:47 +0100 Subject: [PATCH 032/138] Fix a strange issue --- .../android/datamodel/UploadsStorageManager.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/com/owncloud/android/datamodel/UploadsStorageManager.java b/src/com/owncloud/android/datamodel/UploadsStorageManager.java index 3abfcd0ae1b2..10c398690e94 100644 --- a/src/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/src/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -399,13 +399,15 @@ private List getPendingJobs() { ArrayList list = new ArrayList<>(); - for (JobInfo ji: js.getAllPendingJobs()) { - PersistableBundle extras = ji.getExtras(); - OCUpload upload = new OCUpload(extras.getString("filePath"), - extras.getString("remotePath"), - extras.getString("account")); - - list.add(upload); + if (js != null) { + for (JobInfo ji : js.getAllPendingJobs()) { + PersistableBundle extras = ji.getExtras(); + OCUpload upload = new OCUpload(extras.getString("filePath"), + extras.getString("remotePath"), + extras.getString("account")); + + list.add(upload); + } } return list; From 172432d38f497fe262984c1bb30cfe59e77895d9 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 6 Feb 2017 23:39:23 +0100 Subject: [PATCH 033/138] Properly separate auto upload settings by acc --- src/com/owncloud/android/MainApp.java | 2 -- .../android/ui/activity/FolderSyncActivity.java | 12 +++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index d218a6f88b56..b0f0d402d2ad 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -45,8 +45,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - /** * Main Application of the project diff --git a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java index 4630ab0be70f..d3a7b8ae8719 100644 --- a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java +++ b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java @@ -21,6 +21,7 @@ package com.owncloud.android.ui.activity; +import android.accounts.Account; import android.content.Intent; import android.os.Bundle; import android.os.Handler; @@ -130,7 +131,16 @@ private void load(final int perFolderMediaItemLimit) { public void run() { final List mediaFolders = MediaProvider.getMediaFolders(getContentResolver(), perFolderMediaItemLimit); - syncFolderItems = sortSyncedFolderItems(mergeFolderData(mSyncedFolderProvider.getSyncedFolders(), + List syncedFolderArrayList = mSyncedFolderProvider.getSyncedFolders(); + List currentAccountSyncedFoldersList = new ArrayList(); + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(FolderSyncActivity.this); + for (SyncedFolder syncedFolder : syncedFolderArrayList) { + if (syncedFolder.getAccount().equals(currentAccount.name)) { + currentAccountSyncedFoldersList.add(syncedFolder); + } + } + + syncFolderItems = sortSyncedFolderItems(mergeFolderData(currentAccountSyncedFoldersList, mediaFolders)); mHandler.post(new TimerTask() { From 52d36713955c9548e5940453604b5f496f55767d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 00:00:17 +0100 Subject: [PATCH 034/138] Show upload for current account only --- .../datamodel/UploadsStorageManager.java | 57 ++++++++++++++----- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/src/com/owncloud/android/datamodel/UploadsStorageManager.java b/src/com/owncloud/android/datamodel/UploadsStorageManager.java index 10c398690e94..197adc8ccf00 100644 --- a/src/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/src/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -20,6 +20,7 @@ */ package com.owncloud.android.datamodel; +import android.accounts.Account; import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.content.ContentResolver; @@ -31,6 +32,7 @@ import android.os.PersistableBundle; import android.support.annotation.RequiresApi; +import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.db.OCUpload; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; import com.owncloud.android.db.UploadResult; @@ -376,7 +378,10 @@ private OCUpload createOCUploadFromCursor(Cursor c) { */ public OCUpload[] getCurrentAndPendingUploads() { + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + OCUpload[] uploads = getUploads( + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_WIFI.getValue() + " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_CHARGING.getValue(), @@ -397,16 +402,20 @@ public OCUpload[] getCurrentAndPendingUploads() { private List getPendingJobs() { JobScheduler js = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + ArrayList list = new ArrayList<>(); if (js != null) { for (JobInfo ji : js.getAllPendingJobs()) { PersistableBundle extras = ji.getExtras(); - OCUpload upload = new OCUpload(extras.getString("filePath"), - extras.getString("remotePath"), - extras.getString("account")); + if (extras.get("account").equals(currentAccount.name)) { + OCUpload upload = new OCUpload(extras.getString("filePath"), + extras.getString("remotePath"), + extras.getString("account")); - list.add(upload); + list.add(upload); + } } } @@ -417,12 +426,14 @@ private List getPendingJobs() { public void cancelPendingJob(String accountName, String remotePath){ JobScheduler js = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); - for (JobInfo ji: js.getAllPendingJobs()) { - PersistableBundle extras = ji.getExtras(); - if (remotePath.equalsIgnoreCase(extras.getString("remotePath")) && - accountName.equalsIgnoreCase(extras.getString("account"))){ - js.cancel(ji.getId()); - break; + if (js != null) { + for (JobInfo ji : js.getAllPendingJobs()) { + PersistableBundle extras = ji.getExtras(); + if (remotePath.equalsIgnoreCase(extras.getString("remotePath")) && + accountName.equalsIgnoreCase(extras.getString("account"))) { + js.cancel(ji.getId()); + break; + } } } } @@ -431,14 +442,21 @@ public void cancelPendingJob(String accountName, String remotePath){ * Get all failed uploads. */ public OCUpload[] getFailedUploads() { - return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value, null); + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + + return getUploads( + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value, null); } /** * Get all uploads which where successfully completed. */ public OCUpload[] getFinishedUploads() { - return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value, null); + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + + return getUploads(ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value, null); } /** @@ -446,8 +464,11 @@ public OCUpload[] getFinishedUploads() { * @return Array of failed uploads, except for those that were not performed due to lack of Wifi connection. */ public OCUpload[] getFailedButNotDelayedUploads() { + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + return getUploads( - ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + AND + + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + AND + ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + AND + ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(), null @@ -459,9 +480,11 @@ private ContentResolver getDB() { } public long clearFailedButNotDelayedUploads() { + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); long result = getDB().delete( ProviderTableMeta.CONTENT_URI_UPLOADS, - ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + AND + + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + AND + ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + AND + ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(), null @@ -474,8 +497,11 @@ public long clearFailedButNotDelayedUploads() { } public long clearSuccessfulUploads() { + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + long result = getDB().delete( ProviderTableMeta.CONTENT_URI_UPLOADS, + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + ProviderTableMeta.UPLOADS_STATUS + "=="+ UploadStatus.UPLOAD_SUCCEEDED.value, null ); Log_OC.d(TAG, "delete all successful uploads"); @@ -486,11 +512,14 @@ public long clearSuccessfulUploads() { } public long clearAllFinishedButNotDelayedUploads() { + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); + String[] whereArgs = new String[2]; whereArgs[0] = String.valueOf(UploadStatus.UPLOAD_SUCCEEDED.value); whereArgs[1] = String.valueOf(UploadStatus.UPLOAD_FAILED.value); long result = getDB().delete( ProviderTableMeta.CONTENT_URI_UPLOADS, + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "==\"" + currentAccount.name + "\" AND " + ProviderTableMeta.UPLOADS_STATUS + "=? OR " + ProviderTableMeta.UPLOADS_STATUS + "=? AND " + ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + AND + ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(), From b78051cf73f7c9433d091e769cbb8d1b65eda1bc Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 00:02:16 +0100 Subject: [PATCH 035/138] Fix a typo --- .../android/services/observer/SyncedFolderObserverService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 79d06ef7deed..20e5bbcedd31 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -116,7 +116,7 @@ public boolean accept(File pathname) { Log_OC.d(TAG, "start"); if (pairArrayList.size() == 0) { for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { - if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) { + if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder)) { Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( syncedFolder.getLocalPath()), fileFilter); From 2be9cec609b5cff29cd0474cdae826f5dcee2cc2 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 00:10:34 +0100 Subject: [PATCH 036/138] Some progress on mitigating persistance issues --- src/com/owncloud/android/MainApp.java | 1 + .../observer/SyncedFolderObserverService.java | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index b0f0d402d2ad..522c20ee6006 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -151,6 +151,7 @@ public void onActivitySaveInstanceState(Activity activity, Bundle outState) { @Override public void onActivityDestroyed(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending" ); + MainApp.getSyncedFolderObserverService().syncToDisk(false); } }); } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 20e5bbcedd31..b8bd821432c3 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -205,8 +205,7 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) } - @Override - public void onDestroy() { + public void syncToDisk(boolean destructive) { for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); for (int i = 0; i < pairArrayList.size(); i++) { @@ -218,8 +217,11 @@ public void onDestroy() { break; } } - monitor.removeObserver(obs); - syncedFolderMap.remove(obs); + + if (destructive) { + monitor.removeObserver(obs); + syncedFolderMap.remove(obs); + } try { obs.destroy(); @@ -228,9 +230,21 @@ public void onDestroy() { } } + if (destructive) { + try { + monitor.stop(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onDestroy"); + } + } writePersistenceEntries(false, file); } + @Override + public void onDestroy() { + syncToDisk(true); + } + /** * Restart oberver if it is enabled * If syncedFolder exists already, use it, otherwise create new observer From 54545a9337b4817f30ce115a0aea3f9ee38af028 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 00:13:24 +0100 Subject: [PATCH 037/138] Progress on fixing persistance disk sync --- src/com/owncloud/android/MainApp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 522c20ee6006..f4a0e8647a83 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -135,6 +135,7 @@ public void onActivityResumed(Activity activity) { @Override public void onActivityPaused(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending"); + MainApp.getSyncedFolderObserverService().syncToDisk(false); } @Override @@ -151,7 +152,6 @@ public void onActivitySaveInstanceState(Activity activity, Bundle outState) { @Override public void onActivityDestroyed(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending" ); - MainApp.getSyncedFolderObserverService().syncToDisk(false); } }); } From 2a3e38d1ebbe098cc3e56c480d3bc6776668e539 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 10:59:04 +0100 Subject: [PATCH 038/138] Fix a crashing bug --- src/com/owncloud/android/MainApp.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index f4a0e8647a83..599c7664ab3e 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -135,7 +135,9 @@ public void onActivityResumed(Activity activity) { @Override public void onActivityPaused(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending"); - MainApp.getSyncedFolderObserverService().syncToDisk(false); + if (MainApp.getSyncedFolderObserverService() != null) { + MainApp.getSyncedFolderObserverService().syncToDisk(false); + } } @Override From 1e905353b5c56324e71f9fd6944b438052074966 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 11:03:07 +0100 Subject: [PATCH 039/138] Change to onStop --- src/com/owncloud/android/MainApp.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 599c7664ab3e..1253ea016a71 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -135,15 +135,15 @@ public void onActivityResumed(Activity activity) { @Override public void onActivityPaused(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending"); - if (MainApp.getSyncedFolderObserverService() != null) { - MainApp.getSyncedFolderObserverService().syncToDisk(false); - } } @Override public void onActivityStopped(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending" ); PassCodeManager.getPassCodeManager().onActivityStopped(activity); + if (MainApp.getSyncedFolderObserverService() != null) { + MainApp.getSyncedFolderObserverService().syncToDisk(false); + } } @Override From 697b05f031a87754e251c37282925d2fdfe6eb0f Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 12:20:40 +0100 Subject: [PATCH 040/138] Hopefully fix double upload issue --- .../observer/SyncedFolderObserverService.java | 87 ++++++++++++------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index b8bd821432c3..6b6beeedaa22 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -6,17 +6,17 @@ * @author Mario Danic * Copyright (C) 2016 Tobias Kaminsky, Andy Scherzinger * Copyright (C) 2017 Mario Danic - * + *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + *

* You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -77,15 +77,15 @@ public boolean accept(File pathname) { boolean readPerstistanceEntries = false; - if (file.exists() ) { + if (file.exists()) { FileInputStream fis = null; try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); boolean cont = true; - while(cont){ + while (cont) { Object obj = ois.readObject(); - if(obj != null) + if (obj != null) pairArrayList.add((SerializablePair) obj); else cont = false; @@ -136,9 +136,9 @@ public boolean accept(File pathname) { } } } else { - for(int i = 0; i < pairArrayList.size(); i++) { + for (int i = 0; i < pairArrayList.size(); i++) { SyncedFolder syncFolder = pairArrayList.get(i).getKey(); - for(SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { + for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { if (syncFolder.getId() == syncedFolder.getId()) { syncFolder = syncedFolder; pairArrayList.set(i, new SerializablePair(syncFolder, @@ -182,7 +182,7 @@ private void writePersistenceEntries(boolean readPerstistanceEntries, File file) if (!newFile.exists()) { newFile.createNewFile(); } - fos = new FileOutputStream (new File(file.getAbsolutePath()), false); + fos = new FileOutputStream(new File(file.getAbsolutePath()), false); ObjectOutputStream os = new ObjectOutputStream(fos); for (int i = 0; i < pairArrayList.size(); i++) { os.writeObject(pairArrayList.get(i)); @@ -254,35 +254,42 @@ public void onDestroy() { public void restartObserver(SyncedFolder syncedFolder) { FileAlterationMagicObserver fileAlterationObserver; - if (syncedFolderMap.containsKey(syncedFolder)) { - Log_OC.d(TAG, "stop observer: " + syncedFolder.getLocalPath()); - fileAlterationObserver = syncedFolderMap.get(syncedFolder); - monitor.removeObserver(fileAlterationObserver); - try { - fileAlterationObserver.destroy(); - } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong at onDestroy"); - } + Log_OC.d(TAG, "stop observer: " + syncedFolder.getLocalPath()); - // remove it from the paired array list - for (int i = 0; i < pairArrayList.size(); i++) { - if (syncedFolder.equals(pairArrayList.get(i).getKey())) { - pairArrayList.remove(i); - break; - } + SyncedFolder syncy = null; + for (SyncedFolder syncyFolder : syncedFolderMap.keySet()) { + if (syncyFolder.getId() == syncedFolder.getId()) { + syncy = syncyFolder; + break; } - syncedFolderMap.remove(syncedFolder); } + if (syncedFolder.isEnabled()) { - Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - if (syncedFolderMap.containsKey(syncedFolder)) { - fileAlterationObserver = syncedFolderMap.get(syncedFolder); - if (fileAlterationObserver.getListeners() == null) { - fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); - } + if (syncy != null) { + Log_OC.d(TAG, "start observer Restart: " + syncedFolder.getLocalPath() + " " + syncedFolder.getAccount()); + fileAlterationObserver = syncedFolderMap.get(syncy); + monitor.removeObserver(fileAlterationObserver); + fileAlterationObserver.removeListener(null); + fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + syncedFolderMap.remove(syncy); + syncedFolderMap.put(syncedFolder, fileAlterationObserver); monitor.addObserver(fileAlterationObserver); + + // remove it from the paired array list + for (int i = 0; i < pairArrayList.size(); i++) { + if (syncy.getId() == pairArrayList.get(i).getKey().getId()) { + pairArrayList.remove(i); + break; + } + } + + pairArrayList.add(new SerializablePair(syncedFolder, + fileAlterationObserver.getRootEntry())); + } else { + Log_OC.d(TAG, "start observer Restart noMap: " + syncedFolder.getLocalPath() + " " + syncedFolder.getAccount()); + fileAlterationObserver = new FileAlterationMagicObserver(new File(syncedFolder.getLocalPath()), fileFilter); @@ -304,6 +311,24 @@ public void restartObserver(SyncedFolder syncedFolder) { } } + } else { + fileAlterationObserver = syncedFolderMap.get(syncy); + monitor.removeObserver(fileAlterationObserver); + + try { + fileAlterationObserver.destroy(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong at onDestroy"); + } + + // remove it from the paired array list + for (int i = 0; i < pairArrayList.size(); i++) { + if (syncy.getId() == pairArrayList.get(i).getKey().getId()) { + pairArrayList.remove(i); + break; + } + } + syncedFolderMap.remove(syncy); } writePersistenceEntries(false, file); From f2d508acf3e1fbda9ed372c93d6b10e4d973c368 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 13:49:09 +0100 Subject: [PATCH 041/138] Fix legacy sync folder entries --- src/com/owncloud/android/MainApp.java | 115 ++++++++++++------ .../datamodel/SyncedFolderProvider.java | 25 ++++ 2 files changed, 102 insertions(+), 38 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 1253ea016a71..d07f18dcd8e7 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -1,22 +1,21 @@ /** - * ownCloud Android client application - * - * @author masensio - * @author David A. Velasco - * Copyright (C) 2015 ownCloud Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * ownCloud Android client application * + * @author masensio + * @author David A. Velasco + * Copyright (C) 2015 ownCloud Inc. + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package com.owncloud.android; @@ -33,8 +32,11 @@ import android.os.Environment; import android.os.IBinder; import android.preference.PreferenceManager; +import android.support.v4.util.Pair; import com.owncloud.android.authentication.PassCodeManager; +import com.owncloud.android.datamodel.SyncedFolder; +import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy; @@ -43,12 +45,15 @@ import com.owncloud.android.ui.activity.Preferences; import com.owncloud.android.ui.activity.WhatsNewActivity; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * Main Application of the project - * + * * Contains methods to build the "static" strings. These strings were before constants in different * classes */ @@ -74,14 +79,15 @@ public class MainApp extends Application { @SuppressWarnings("unused") private boolean mBound; - @SuppressFBWarnings("ST") public void onCreate(){ + @SuppressFBWarnings("ST") + public void onCreate() { super.onCreate(); MainApp.mContext = getApplicationContext(); SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); MainApp.storagePath = appPrefs.getString(Preferences.PreferenceKeys.STORAGE_PATH, Environment. - getExternalStorageDirectory().getAbsolutePath()); + getExternalStorageDirectory().getAbsolutePath()); boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso)); @@ -94,7 +100,7 @@ public class MainApp extends Application { // initialise thumbnails cache on background thread new ThumbnailsCacheManager.InitDiskCacheTask().execute(); - + if (BuildConfig.DEBUG) { String dataFolder = getDataFolder(); @@ -106,30 +112,63 @@ public class MainApp extends Application { Log_OC.d("Debug", "start logging"); } + // clean broken synced folder entries + if (!PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("legacyClean", false)) { + SyncedFolderProvider mProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); + + List syncedFolderList = mProvider.getSyncedFolders(); + Map, Long> syncedFolders = new HashMap<>(); + ArrayList ids = new ArrayList<>(); + ArrayList syncedFolderArrayList = new ArrayList<>(); + for (SyncedFolder syncedFolder : syncedFolderList) { + Pair checkPair = new Pair(syncedFolder.getAccount(), syncedFolder.getLocalPath()); + if (syncedFolders.containsKey(checkPair)) { + if (syncedFolder.getId() > syncedFolders.get(checkPair)) { + syncedFolders.put(checkPair, syncedFolder.getId()); + } + } else { + syncedFolders.put(checkPair, syncedFolder.getId()); + } + } + + for (Long value : syncedFolders.values()) { + ids.add(value); + } + + for (SyncedFolder syncedFolder : syncedFolderList) { + if (ids.contains(syncedFolder.getId())) { + syncedFolderArrayList.add(syncedFolder); + } + } + + mProvider.deleteSyncFolders(mContext, syncedFolderArrayList, ids); + } + Log_OC.d("SyncedFolderObserverService", "Start service SyncedFolderObserverService"); Intent i = new Intent(this, SyncedFolderObserverService.class); startService(i); bindService(i, syncedFolderObserverServiceConnection, Context.BIND_AUTO_CREATE); + // register global protection with pass code - registerActivityLifecycleCallbacks( new ActivityLifecycleCallbacks() { + registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - Log_OC.d(activity.getClass().getSimpleName(), "onCreate(Bundle) starting" ); + Log_OC.d(activity.getClass().getSimpleName(), "onCreate(Bundle) starting"); WhatsNewActivity.runIfNeeded(activity); PassCodeManager.getPassCodeManager().onActivityCreated(activity); } @Override public void onActivityStarted(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onStart() starting" ); + Log_OC.d(activity.getClass().getSimpleName(), "onStart() starting"); PassCodeManager.getPassCodeManager().onActivityStarted(activity); } @Override public void onActivityResumed(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onResume() starting" ); + Log_OC.d(activity.getClass().getSimpleName(), "onResume() starting"); } @Override @@ -139,7 +178,7 @@ public void onActivityPaused(Activity activity) { @Override public void onActivityStopped(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending" ); + Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending"); PassCodeManager.getPassCodeManager().onActivityStopped(activity); if (MainApp.getSyncedFolderObserverService() != null) { MainApp.getSyncedFolderObserverService().syncToDisk(false); @@ -148,12 +187,12 @@ public void onActivityStopped(Activity activity) { @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - Log_OC.d(activity.getClass().getSimpleName(), "onSaveInstanceState(Bundle) starting" ); + Log_OC.d(activity.getClass().getSimpleName(), "onSaveInstanceState(Bundle) starting"); } @Override public void onActivityDestroyed(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending" ); + Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending"); } }); } @@ -162,11 +201,11 @@ public static Context getAppContext() { return MainApp.mContext; } - public static String getStoragePath(){ + public static String getStoragePath() { return MainApp.storagePath; } - public static void setStoragePath(String path){ + public static void setStoragePath(String path) { MainApp.storagePath = path; } @@ -193,42 +232,42 @@ public static int getVersionCode() { public static String getAuthority() { return getAppContext().getResources().getString(R.string.authority); } - + // From AccountAuthenticator // public static final String AUTH_TOKEN_TYPE = "org.owncloud"; public static String getAuthTokenType() { return getAppContext().getResources().getString(R.string.authority); } - + // From ProviderMeta // public static final String DB_FILE = "owncloud.db"; public static String getDBFile() { return getAppContext().getResources().getString(R.string.db_file); } - + // From ProviderMeta // private final String mDatabaseName = "ownCloud"; public static String getDBName() { return getAppContext().getResources().getString(R.string.db_name); } - + /** * name of data_folder, e.g., "owncloud" */ public static String getDataFolder() { return getAppContext().getResources().getString(R.string.data_folder); } - + // log_name public static String getLogName() { return getAppContext().getResources().getString(R.string.log_name); } - public static void showOnlyFilesOnDevice(boolean state){ + public static void showOnlyFilesOnDevice(boolean state) { mOnlyOnDevice = state; } - public static boolean isOnlyOnDevice(){ + public static boolean isOnlyOnDevice() { return mOnlyOnDevice; } diff --git a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java index 425bf912ff21..6a576a7b8777 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -21,8 +21,10 @@ import android.content.ContentResolver; import android.content.ContentValues; +import android.content.Context; import android.database.Cursor; import android.net.Uri; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import com.owncloud.android.MainApp; @@ -186,6 +188,29 @@ public SyncedFolder findByLocalPath(String localPath) { } + public int deleteSyncFolders(Context context, ArrayList syncedFolders, ArrayList ids) { + + + int result = mContentResolver.delete( + ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS, + ProviderMeta.ProviderTableMeta._ID + " IN (?)", + new String[]{String.valueOf(ids)} + ); + + if (result > 0) { + for (SyncedFolder syncedFolder : syncedFolders) { + notifyFolderSyncObservers(syncedFolder); + } + + if (context != null) { + PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("legacyClean", true).apply(); + } + } + + return result; + + + } /** * update given synced folder. * From 6ea9d1eb10b2f15fb9ea8ee78f85068942f303d8 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 14:06:30 +0100 Subject: [PATCH 042/138] Fix build --- src/com/owncloud/android/MainApp.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index d07f18dcd8e7..3b99407278af 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -50,6 +50,8 @@ import java.util.List; import java.util.Map; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Main Application of the project From 123e812acf7291686c36c9ae7604c59051cecdf3 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 14:09:24 +0100 Subject: [PATCH 043/138] Fix cleanup --- src/com/owncloud/android/MainApp.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 3b99407278af..c68ae3e2b4da 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -119,22 +119,24 @@ public void onCreate() { SyncedFolderProvider mProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); List syncedFolderList = mProvider.getSyncedFolders(); - Map, Long> syncedFolders = new HashMap<>(); + Map, Pair> syncedFolders = new HashMap<>(); ArrayList ids = new ArrayList<>(); ArrayList syncedFolderArrayList = new ArrayList<>(); for (SyncedFolder syncedFolder : syncedFolderList) { Pair checkPair = new Pair(syncedFolder.getAccount(), syncedFolder.getLocalPath()); if (syncedFolders.containsKey(checkPair)) { - if (syncedFolder.getId() > syncedFolders.get(checkPair)) { - syncedFolders.put(checkPair, syncedFolder.getId()); + if (syncedFolder.getId() > syncedFolders.get(checkPair).first) { + syncedFolders.put(checkPair, new Pair(syncedFolder.getId(), true)); } } else { - syncedFolders.put(checkPair, syncedFolder.getId()); + syncedFolders.put(checkPair, new Pair(syncedFolder.getId(), false)); } } - for (Long value : syncedFolders.values()) { - ids.add(value); + for (Pair pair : syncedFolders.values()) { + if (pair.second) { + ids.add(pair.first); + } } for (SyncedFolder syncedFolder : syncedFolderList) { From 3b143a91b226e6f1f3baef43d8f8b413e661f720 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 7 Feb 2017 15:01:50 +0100 Subject: [PATCH 044/138] Delete from runnable on delete --- .../owncloud/android/services/FileAlterationMagicListener.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index ff89a780c87e..fa706b1a44fb 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -135,6 +135,7 @@ public void onFileChange(File file) { public void onFileDelete(File file) { if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); + fileRunnable.remove(file.getAbsolutePath()); } } From fbdcfce69211959aa9ef048a1f34eebdfd280ab0 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 8 Feb 2017 05:28:21 +0100 Subject: [PATCH 045/138] Attempt to fix uploads with non-conf folders --- .../observer/SyncedFolderObserverService.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 6b6beeedaa22..e12bcf280583 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -136,6 +136,7 @@ public boolean accept(File pathname) { } } } else { + int foundLocation = -1; for (int i = 0; i < pairArrayList.size(); i++) { SyncedFolder syncFolder = pairArrayList.get(i).getKey(); for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { @@ -143,18 +144,23 @@ public boolean accept(File pathname) { syncFolder = syncedFolder; pairArrayList.set(i, new SerializablePair(syncFolder, pairArrayList.get(i).getValue())); + foundLocation = i; break; } } - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( - syncFolder.getLocalPath()), fileFilter); - observer.setRootEntry(pairArrayList.get(i).getValue()); + if (syncFolder.isEnabled()) { + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( + syncFolder.getLocalPath()), fileFilter); + observer.setRootEntry(pairArrayList.get(i).getValue()); - observer.addListener(new FileAlterationMagicListener(syncFolder)); - monitor.addObserver(observer); - syncedFolderMap.put(syncFolder, observer); + observer.addListener(new FileAlterationMagicListener(syncFolder)); + monitor.addObserver(observer); + syncedFolderMap.put(syncFolder, observer); + } else { + pairArrayList.remove(foundLocation); + } } } From 7f28c35b346d02cafc55283c410e0e8c7cf0c81e Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 8 Feb 2017 05:28:42 +0100 Subject: [PATCH 046/138] :) --- .../services/observer/SyncedFolderObserverService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index e12bcf280583..f3e8590c287f 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -136,7 +136,6 @@ public boolean accept(File pathname) { } } } else { - int foundLocation = -1; for (int i = 0; i < pairArrayList.size(); i++) { SyncedFolder syncFolder = pairArrayList.get(i).getKey(); for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { @@ -144,7 +143,6 @@ public boolean accept(File pathname) { syncFolder = syncedFolder; pairArrayList.set(i, new SerializablePair(syncFolder, pairArrayList.get(i).getValue())); - foundLocation = i; break; } } @@ -158,7 +156,7 @@ public boolean accept(File pathname) { monitor.addObserver(observer); syncedFolderMap.put(syncFolder, observer); } else { - pairArrayList.remove(foundLocation); + pairArrayList.remove(i); } } From 4068eb5499855bc144e956aba3bacbcb319fa250 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 8 Feb 2017 05:55:07 +0100 Subject: [PATCH 047/138] Attempt to fix duplicate entries --- src/com/owncloud/android/MainApp.java | 6 ++---- .../owncloud/android/datamodel/SyncedFolderProvider.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index c68ae3e2b4da..7cad6354eda5 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -134,13 +134,11 @@ public void onCreate() { } for (Pair pair : syncedFolders.values()) { - if (pair.second) { - ids.add(pair.first); - } + ids.add(pair.first); } for (SyncedFolder syncedFolder : syncedFolderList) { - if (ids.contains(syncedFolder.getId())) { + if (!ids.contains(syncedFolder.getId())) { syncedFolderArrayList.add(syncedFolder); } } diff --git a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java index 6a576a7b8777..a288126cd784 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -193,7 +193,7 @@ public int deleteSyncFolders(Context context, ArrayList syncedFold int result = mContentResolver.delete( ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS, - ProviderMeta.ProviderTableMeta._ID + " IN (?)", + ProviderMeta.ProviderTableMeta._ID + " NOT IN (?)", new String[]{String.valueOf(ids)} ); From ee0c112ffc7681c6b846d78c9c3030d2bc857fb4 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 8 Feb 2017 12:44:48 +0100 Subject: [PATCH 048/138] Increase delay slightly --- .../android/services/FileAlterationMagicListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index fa706b1a44fb..7bd5a07630c9 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -119,7 +119,7 @@ public void run() { }; fileRunnable.put(file.getAbsolutePath(), runnable); - handler.postDelayed(runnable, 500); + handler.postDelayed(runnable, 1500); } @@ -127,7 +127,7 @@ public void run() { public void onFileChange(File file) { if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); - handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 500); + handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 1500); } } From 2015851faab34c34f4c27d4d4900149c1ae23914 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 10 Feb 2017 17:06:58 +0100 Subject: [PATCH 049/138] Attempt to fix duplicate uploads again :P --- .../observer/SyncedFolderObserverService.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index f3e8590c287f..6b6beeedaa22 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -147,18 +147,14 @@ public boolean accept(File pathname) { } } - if (syncFolder.isEnabled()) { - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( - syncFolder.getLocalPath()), fileFilter); - observer.setRootEntry(pairArrayList.get(i).getValue()); + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( + syncFolder.getLocalPath()), fileFilter); + observer.setRootEntry(pairArrayList.get(i).getValue()); - observer.addListener(new FileAlterationMagicListener(syncFolder)); - monitor.addObserver(observer); - syncedFolderMap.put(syncFolder, observer); - } else { - pairArrayList.remove(i); + observer.addListener(new FileAlterationMagicListener(syncFolder)); + monitor.addObserver(observer); + syncedFolderMap.put(syncFolder, observer); - } } } From 050fb0987d4b5bbc6360aa8c6fbafecd5b87bfba Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Fri, 10 Feb 2017 18:06:03 +0100 Subject: [PATCH 050/138] Backup everything --- AndroidManifest.xml | 1 - res/xml/my_backup_rules.xml | 4 ---- 2 files changed, 5 deletions(-) delete mode 100644 res/xml/my_backup_rules.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a90f279b82b5..e8c1a2842147 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -59,7 +59,6 @@ - - - From d1dc7b090ca605df8af4119515c8cc2f7320112c Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 12 Feb 2017 14:25:56 +0100 Subject: [PATCH 051/138] Clean up cleaning --- src/com/owncloud/android/MainApp.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 7cad6354eda5..baabe978fc2b 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -143,7 +143,11 @@ public void onCreate() { } } - mProvider.deleteSyncFolders(mContext, syncedFolderArrayList, ids); + if (ids.size() > 0) { + mProvider.deleteSyncFolders(mContext, syncedFolderArrayList, ids); + } else { + PreferenceManager.getDefaultSharedPreferences(mContext).edit().putBoolean("legacyClean", true).apply(); + } } Log_OC.d("SyncedFolderObserverService", "Start service SyncedFolderObserverService"); From 15101bf6643fd6ceb7d552e73e34311c3051f480 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 13 Feb 2017 09:01:13 +0100 Subject: [PATCH 052/138] Simplify new auto upload code --- .../services/FileAlterationMagicListener.java | 72 ++++--- .../observer/FileAlterationMagicObserver.java | 18 +- .../observer/SyncedFolderObserverService.java | 201 +++++------------- 3 files changed, 103 insertions(+), 188 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 7bd5a07630c9..2fea7f500b24 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -83,43 +83,45 @@ public void onDirectoryDelete(File directory) { @Override public void onFileCreate(final File file) { - final Runnable runnable = new Runnable() { - @Override - public void run() { - PersistableBundle bundle = new PersistableBundle(); - // TODO extract - bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); - bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( - syncedFolder.getRemotePath(), file.getName(), - new Date().getTime(), - syncedFolder.getSubfolderByDate())); - bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); - bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); - - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - Long date = new Date().getTime(); - JobInfo job = new JobInfo.Builder( - date.intValue(), - new ComponentName(context, SyncedFolderJobService.class)) - .setRequiresCharging(syncedFolder.getChargingOnly()) - .setMinimumLatency(10000) - .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) - .setExtras(bundle) - .setPersisted(true) - .build(); - - Integer result = js.schedule(job); - if (result <= 0) { - Log_OC.d(TAG, "Job failed to start: " + result); + if (file != null) { + final Runnable runnable = new Runnable() { + @Override + public void run() { + PersistableBundle bundle = new PersistableBundle(); + // TODO extract + bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); + bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( + syncedFolder.getRemotePath(), file.getName(), + new Date().getTime(), + syncedFolder.getSubfolderByDate())); + bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); + bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); + + JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + Long date = new Date().getTime(); + JobInfo job = new JobInfo.Builder( + date.intValue(), + new ComponentName(context, SyncedFolderJobService.class)) + .setRequiresCharging(syncedFolder.getChargingOnly()) + .setMinimumLatency(10000) + .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) + .setExtras(bundle) + .setPersisted(true) + .build(); + + Integer result = js.schedule(job); + if (result <= 0) { + Log_OC.d(TAG, "Job failed to start: " + result); + } + + fileRunnable.remove(file.getAbsolutePath()); } + }; - fileRunnable.remove(file.getAbsolutePath()); - } - }; - - fileRunnable.put(file.getAbsolutePath(), runnable); - handler.postDelayed(runnable, 1500); + fileRunnable.put(file.getAbsolutePath(), runnable); + handler.postDelayed(runnable, 1500); + } } diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index c7b92a6235e7..760abc12477f 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -34,6 +34,8 @@ */ package com.owncloud.android.services.observer; +import com.owncloud.android.datamodel.SyncedFolder; + import org.apache.commons.io.FileUtils; import org.apache.commons.io.comparator.NameFileComparator; import org.apache.commons.io.monitor.FileAlterationListener; @@ -55,18 +57,28 @@ public class FileAlterationMagicObserver extends FileAlterationObserver implemen private FileEntry rootEntry; private FileFilter fileFilter; private Comparator comparator; + private SyncedFolder syncedFolder; static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; - public FileAlterationMagicObserver(File directory, FileFilter fileFilter) { - super(directory, fileFilter); + public FileAlterationMagicObserver(SyncedFolder syncedFolder, FileFilter fileFilter) { + super(syncedFolder.getLocalPath(), fileFilter); - this.rootEntry = new FileEntry(directory); + this.rootEntry = new FileEntry(new File(syncedFolder.getLocalPath())); this.fileFilter = fileFilter; + this.syncedFolder = syncedFolder; comparator = NameFileComparator.NAME_SYSTEM_COMPARATOR; } + public long getSyncedFolderID() { + return syncedFolder.getId(); + } + + public SyncedFolder getSyncedFolder() { + return syncedFolder; + } + /** * Return the directory being observed. * diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 6b6beeedaa22..35dd65f63af6 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -36,6 +36,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationMonitor; +import org.apache.commons.io.monitor.FileAlterationObserver; import org.apache.commons.io.monitor.FileEntry; import java.io.EOFException; @@ -47,13 +48,11 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.HashMap; import java.util.concurrent.CopyOnWriteArrayList; public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; private SyncedFolderProvider mProvider; - private HashMap syncedFolderMap = new HashMap<>(); private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; @@ -113,52 +112,36 @@ public boolean accept(File pathname) { } - Log_OC.d(TAG, "start"); - if (pairArrayList.size() == 0) { + + if (readPerstistanceEntries && pairArrayList.size() > 0) { + for (int i = 0; i < pairArrayList.size(); i++) { + SyncedFolder syncFolder = pairArrayList.get(i).getKey(); + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncFolder, fileFilter); + observer.setRootEntry(pairArrayList.get(i).getValue()); + observer.addListener(new FileAlterationMagicListener(syncFolder)); + monitor.addObserver(observer); + + } + } else { for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { - if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder)) { - Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath()); - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( - syncedFolder.getLocalPath()), fileFilter); + if (syncedFolder.isEnabled()) { + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncedFolder, fileFilter); try { observer.init(); - SerializablePair pair = new SerializablePair<>(syncedFolder, - observer.getRootEntry()); - pairArrayList.add(pair); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); } observer.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(observer); - syncedFolderMap.put(syncedFolder, observer); } } - } else { - for (int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder syncFolder = pairArrayList.get(i).getKey(); - for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { - if (syncFolder.getId() == syncedFolder.getId()) { - syncFolder = syncedFolder; - pairArrayList.set(i, new SerializablePair(syncFolder, - pairArrayList.get(i).getValue())); - break; - } - } - - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File( - syncFolder.getLocalPath()), fileFilter); - observer.setRootEntry(pairArrayList.get(i).getValue()); - - observer.addListener(new FileAlterationMagicListener(syncFolder)); - monitor.addObserver(observer); - syncedFolderMap.put(syncFolder, observer); - - } } - writePersistenceEntries(readPerstistanceEntries, file); + if (!readPerstistanceEntries) { + syncToDisk(false); + } try { monitor.start(); @@ -173,71 +156,53 @@ public int onStartCommand(Intent intent, int flags, int startId) { return Service.START_NOT_STICKY; } - private void writePersistenceEntries(boolean readPerstistanceEntries, File file) { - FileOutputStream fos = null; + public void syncToDisk(boolean destructive) { + pairArrayList = new CopyOnWriteArrayList<>(); + for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { + FileAlterationMagicObserver fileAlterationMagicObserver = + (FileAlterationMagicObserver) fileAlterationObserver; + pairArrayList.add(new SerializablePair(fileAlterationMagicObserver.getSyncedFolder(), + fileAlterationMagicObserver.getRootEntry())); + } - try { - if (pairArrayList.size() > 0 && !readPerstistanceEntries) { + if (pairArrayList.size() > 0) { + try { File newFile = new File(file.getAbsolutePath()); + if (!newFile.exists()) { newFile.createNewFile(); } - fos = new FileOutputStream(new File(file.getAbsolutePath()), false); + FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath()), false); ObjectOutputStream os = new ObjectOutputStream(fos); for (int i = 0; i < pairArrayList.size(); i++) { os.writeObject(pairArrayList.get(i)); } os.close(); - } else if (file.exists() && pairArrayList.size() == 0) { - FileUtils.deleteQuietly(file); - } - - if (fos != null) { - fos.close(); - } - - } catch (FileNotFoundException e) { - Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); - } catch (IOException e) { - Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via IOException"); - } - - - } - public void syncToDisk(boolean destructive) { - for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) { - FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder); - for (int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder pairSyncedFolder = pairArrayList.get(i).getKey(); - if (pairSyncedFolder.equals(syncedFolder)) { - SerializablePair newPairEntry = new SerializablePair<>(syncedFolder, - obs.getRootEntry()); - pairArrayList.set(i, newPairEntry); - break; + if (fos != null) { + fos.close(); } - } - if (destructive) { - monitor.removeObserver(obs); - syncedFolderMap.remove(obs); + } catch (FileNotFoundException e) { + Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); + } catch (IOException e) { + Log_OC.d(TAG, "Failed writing to nc_persisten file via IOException"); } - try { - obs.destroy(); - } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong at onDestroy"); + } else { + if (file.exists()) { + FileUtils.deleteQuietly(file); } } if (destructive) { + monitor.removeObserver(null); try { monitor.stop(); } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong at onDestroy"); + Log_OC.d(TAG, "Failed in stopping monitor"); } } - writePersistenceEntries(false, file); } @Override @@ -253,85 +218,21 @@ public void onDestroy() { */ public void restartObserver(SyncedFolder syncedFolder) { - FileAlterationMagicObserver fileAlterationObserver; - Log_OC.d(TAG, "stop observer: " + syncedFolder.getLocalPath()); - - SyncedFolder syncy = null; - for (SyncedFolder syncyFolder : syncedFolderMap.keySet()) { - if (syncyFolder.getId() == syncedFolder.getId()) { - syncy = syncyFolder; - break; - } - } - - - if (syncedFolder.isEnabled()) { - if (syncy != null) { - Log_OC.d(TAG, "start observer Restart: " + syncedFolder.getLocalPath() + " " + syncedFolder.getAccount()); - fileAlterationObserver = syncedFolderMap.get(syncy); - monitor.removeObserver(fileAlterationObserver); - fileAlterationObserver.removeListener(null); - fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); - syncedFolderMap.remove(syncy); - syncedFolderMap.put(syncedFolder, fileAlterationObserver); - monitor.addObserver(fileAlterationObserver); - - // remove it from the paired array list - for (int i = 0; i < pairArrayList.size(); i++) { - if (syncy.getId() == pairArrayList.get(i).getKey().getId()) { - pairArrayList.remove(i); - break; - } - } - - pairArrayList.add(new SerializablePair(syncedFolder, - fileAlterationObserver.getRootEntry())); - - } else { - Log_OC.d(TAG, "start observer Restart noMap: " + syncedFolder.getLocalPath() + " " + syncedFolder.getAccount()); - - fileAlterationObserver = new FileAlterationMagicObserver(new File(syncedFolder.getLocalPath()), - fileFilter); - - try { - fileAlterationObserver.init(); - SerializablePair pair = new SerializablePair<>(syncedFolder, - fileAlterationObserver.getRootEntry()); - pairArrayList.add(pair); - } catch (Exception e) { - Log_OC.d(TAG, "Failed getting an observer to intialize"); - } - - fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); - monitor.addObserver(fileAlterationObserver); - try { - syncedFolderMap.put(syncedFolder, fileAlterationObserver); - } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong on RestartObserver"); - } - - } - } else { - fileAlterationObserver = syncedFolderMap.get(syncy); - monitor.removeObserver(fileAlterationObserver); - - try { - fileAlterationObserver.destroy(); - } catch (Exception e) { - Log_OC.d(TAG, "Something went very wrong at onDestroy"); - } - - // remove it from the paired array list - for (int i = 0; i < pairArrayList.size(); i++) { - if (syncy.getId() == pairArrayList.get(i).getKey().getId()) { - pairArrayList.remove(i); - break; + for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { + FileAlterationMagicObserver fileAlterationMagicObserver = + (FileAlterationMagicObserver) fileAlterationObserver; + if (fileAlterationMagicObserver.getSyncedFolderID() == syncedFolder.getId()) { + if (syncedFolder.isEnabled()) { + fileAlterationObserver.removeListener(null); + fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + } else { + monitor.removeObserver(fileAlterationObserver); } + return; } - syncedFolderMap.remove(syncy); } - writePersistenceEntries(false, file); + syncToDisk(false); } @Override From 5e4ad8ab14026608262d020ae850a76427ff8672 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Mon, 13 Feb 2017 09:54:44 +0100 Subject: [PATCH 053/138] user last modification date for auto upload, e.g. take an image on 31.01.17 and upload it via autoupload on 10.02.17 it will be uploaded to Camera/2017/01 --- .../android/services/FileAlterationMagicListener.java | 3 +-- src/com/owncloud/android/utils/FileStorageUtils.java | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 2fea7f500b24..38de6de70de0 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -88,11 +88,10 @@ public void onFileCreate(final File file) { @Override public void run() { PersistableBundle bundle = new PersistableBundle(); - // TODO extract bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( syncedFolder.getRemotePath(), file.getName(), - new Date().getTime(), + file.lastModified(), syncedFolder.getSubfolderByDate())); bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java index 1eec561edd01..78247d5557e1 100644 --- a/src/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/com/owncloud/android/utils/FileStorageUtils.java @@ -122,7 +122,7 @@ public static String getLogPath() { * string is returned * * @param date: date in microseconds since 1st January 1970 - * @return + * @return string: yyyy/mm/ */ private static String getSubpathFromDate(long date) { if (date == 0) { @@ -140,11 +140,11 @@ private static String getSubpathFromDate(long date) { } /** - * Returns the InstantUploadFilePath on the owncloud instance + * Returns the InstantUploadFilePath on the nextcloud instance * - * @param fileName + * @param fileName complete file name * @param dateTaken: Time in milliseconds since 1970 when the picture was taken. - * @return + * @return instantUpload path, eg. /Camera/2017/01/fileName */ public static String getInstantUploadFilePath(String remotePath, String fileName, long dateTaken, Boolean subfolderByDate) { From 284eba8fc704cbca6177f29faefe275902dc13ea Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 13 Feb 2017 10:07:09 +0100 Subject: [PATCH 054/138] New build --- .../observer/SyncedFolderObserverService.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 35dd65f63af6..d897da20d4bb 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -35,6 +35,7 @@ import com.owncloud.android.services.FileAlterationMagicListener; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; import org.apache.commons.io.monitor.FileEntry; @@ -218,21 +219,39 @@ public void onDestroy() { */ public void restartObserver(SyncedFolder syncedFolder) { + boolean found = false; + FileAlterationMagicObserver fileAlterationMagicObserver; for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { - FileAlterationMagicObserver fileAlterationMagicObserver = + fileAlterationMagicObserver = (FileAlterationMagicObserver) fileAlterationObserver; if (fileAlterationMagicObserver.getSyncedFolderID() == syncedFolder.getId()) { if (syncedFolder.isEnabled()) { - fileAlterationObserver.removeListener(null); + for (FileAlterationListener fileAlterationListener : fileAlterationMagicObserver.getListeners()) { + fileAlterationMagicObserver.removeListener(fileAlterationListener); + } fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); } else { monitor.removeObserver(fileAlterationObserver); } - return; + found = true; + break; } } + if (!found) { + fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); + try { + fileAlterationMagicObserver.init(); + } catch (Exception e) { + Log_OC.d(TAG, "Failed getting an observer to intialize"); + } + + fileAlterationMagicObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(fileAlterationMagicObserver); + } + syncToDisk(false); + } @Override From 8a56201874e5b4ddf2d606f04c101ef34fc92c40 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 13 Feb 2017 10:49:37 +0100 Subject: [PATCH 055/138] Small workaround --- .../observer/SyncedFolderObserverService.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index d897da20d4bb..4a967618abe0 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -117,11 +117,17 @@ public boolean accept(File pathname) { if (readPerstistanceEntries && pairArrayList.size() > 0) { for (int i = 0; i < pairArrayList.size(); i++) { SyncedFolder syncFolder = pairArrayList.get(i).getKey(); + for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { + if (syncedFolder.getId() == pairArrayList.get(i).getKey().getId()) { + syncFolder = syncedFolder; + break; + } + } + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncFolder, fileFilter); observer.setRootEntry(pairArrayList.get(i).getValue()); observer.addListener(new FileAlterationMagicListener(syncFolder)); monitor.addObserver(observer); - } } else { for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { @@ -140,9 +146,7 @@ public boolean accept(File pathname) { } } - if (!readPerstistanceEntries) { - syncToDisk(false); - } + syncToDisk(false); try { monitor.start(); @@ -238,7 +242,7 @@ public void restartObserver(SyncedFolder syncedFolder) { } } - if (!found) { + if (!found && syncedFolder.isEnabled()) { fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); try { fileAlterationMagicObserver.init(); From 9fcda73119c721aee61857bff7fdeea69646374d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 13 Feb 2017 20:28:02 +0100 Subject: [PATCH 056/138] Attempt a fix --- .../android/utils/FileStorageUtils.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java index 78247d5557e1..f2690893d518 100644 --- a/src/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/com/owncloud/android/utils/FileStorageUtils.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -46,7 +47,6 @@ import java.util.Comparator; import java.util.Date; import java.util.List; -import java.util.Locale; import java.util.Vector; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -128,15 +128,13 @@ private static String getSubpathFromDate(long date) { if (date == 0) { return ""; } - try { - SimpleDateFormat formatter = new SimpleDateFormat( - "yyyy" + OCFile.PATH_SEPARATOR + "MM" + OCFile.PATH_SEPARATOR, Locale.ENGLISH); - return formatter.format(new Date(date)); - } - catch(RuntimeException ex) { - Log_OC.w(TAG, "could not extract date from timestamp"); - return ""; - } + + Date d = new Date(date); + DateFormat df = new SimpleDateFormat("yyyy/MM/"); + + return df.format(d); + + } /** From 79fb4e884b6030f579ff9a4448c21135d95e10e9 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 13 Feb 2017 20:58:19 +0100 Subject: [PATCH 057/138] Use exif tags --- .../services/FileAlterationMagicListener.java | 37 ++++++++++++++++++- .../android/utils/FileStorageUtils.java | 31 +++++++++++++++- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 38de6de70de0..6b6a18e5c058 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -23,8 +23,10 @@ import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; +import android.media.ExifInterface; import android.os.Handler; import android.os.PersistableBundle; +import android.text.TextUtils; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; @@ -35,9 +37,14 @@ import org.apache.commons.io.monitor.FileAlterationObserver; import java.io.File; +import java.io.IOException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import java.util.TimeZone; /** * Magical file alteration listener @@ -84,14 +91,40 @@ public void onDirectoryDelete(File directory) { @Override public void onFileCreate(final File file) { if (file != null) { - final Runnable runnable = new Runnable() { + + String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath()); + Long dateFolder = file.lastModified(); + final Locale current = context.getResources().getConfiguration().locale; + + if (mimetypeString.equalsIgnoreCase("image/jpeg") || mimetypeString.equals("image/tiff")) { + try { + ExifInterface exifInterface = new ExifInterface(file.getAbsolutePath()); + if (!TextUtils.isEmpty(exifInterface.getAttribute(ExifInterface.TAG_DATETIME))) { + String exifDate = exifInterface.getAttribute(ExifInterface.TAG_DATETIME); + ParsePosition pos = new ParsePosition(0); + SimpleDateFormat sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", current); + sFormatter.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID())); + Date datetime = sFormatter.parse(exifDate, pos); + dateFolder = datetime.getTime(); + } + + } catch (IOException e) { + Log_OC.d(TAG, "Failed to get the proper time " + e.getLocalizedMessage()); + } + } + + + final Long finalDateFolder = dateFolder; + + final Runnable runnable = new Runnable() { @Override public void run() { PersistableBundle bundle = new PersistableBundle(); bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( + current, syncedFolder.getRemotePath(), file.getName(), - file.lastModified(), + finalDateFolder, syncedFolder.getSubfolderByDate())); bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java index f2690893d518..c31a67112a6f 100644 --- a/src/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/com/owncloud/android/utils/FileStorageUtils.java @@ -47,6 +47,8 @@ import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Locale; +import java.util.TimeZone; import java.util.Vector; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -124,17 +126,32 @@ public static String getLogPath() { * @param date: date in microseconds since 1st January 1970 * @return string: yyyy/mm/ */ + private static String getSubpathFromDate(long date, Locale currentLocale) { + if (date == 0) { + return ""; + } + + Date d = new Date(date); + + DateFormat df = new SimpleDateFormat("yyyy/MM/", currentLocale); + df.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID())); + + return df.format(d); + + + } + private static String getSubpathFromDate(long date) { if (date == 0) { return ""; } Date d = new Date(date); + DateFormat df = new SimpleDateFormat("yyyy/MM/"); return df.format(d); - } /** @@ -144,15 +161,25 @@ private static String getSubpathFromDate(long date) { * @param dateTaken: Time in milliseconds since 1970 when the picture was taken. * @return instantUpload path, eg. /Camera/2017/01/fileName */ + public static String getInstantUploadFilePath(Locale current, String remotePath, String fileName, long dateTaken, + Boolean subfolderByDate) { + String subPath = ""; + if (subfolderByDate) { + subPath = getSubpathFromDate(dateTaken, current); + } + return remotePath + OCFile.PATH_SEPARATOR + subPath + (fileName == null ? "" : fileName); + } + public static String getInstantUploadFilePath(String remotePath, String fileName, long dateTaken, Boolean subfolderByDate) { String subPath = ""; if (subfolderByDate) { - subPath = getSubpathFromDate(dateTaken); + subPath = getSubpathFromDate(dateTaken); } return remotePath + OCFile.PATH_SEPARATOR + subPath + (fileName == null ? "" : fileName); } + /** * Gets the composed path when video is or must be stored * @param context From 623a48328d0fd3ebd43280aada9c70aa482bb771 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 14 Feb 2017 12:21:11 +0100 Subject: [PATCH 058/138] Simplify code --- src/com/owncloud/android/MainApp.java | 3 - .../observer/SyncedFolderObserverService.java | 124 +----------------- 2 files changed, 1 insertion(+), 126 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index baabe978fc2b..c9b1eddefd77 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -186,9 +186,6 @@ public void onActivityPaused(Activity activity) { public void onActivityStopped(Activity activity) { Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending"); PassCodeManager.getPassCodeManager().onActivityStopped(activity); - if (MainApp.getSyncedFolderObserverService() != null) { - MainApp.getSyncedFolderObserverService().syncToDisk(false); - } } @Override diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 4a967618abe0..9f825fd49fb5 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -34,21 +34,13 @@ import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.FileAlterationMagicListener; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; import org.apache.commons.io.monitor.FileEntry; -import java.io.EOFException; import java.io.File; import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.util.concurrent.CopyOnWriteArrayList; public class SyncedFolderObserverService extends Service { @@ -72,64 +64,7 @@ public boolean accept(File pathname) { } }; - file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + File.separator + - "nc_persistence"); - boolean readPerstistanceEntries = false; - - if (file.exists()) { - FileInputStream fis = null; - try { - fis = new FileInputStream(file); - ObjectInputStream ois = new ObjectInputStream(fis); - boolean cont = true; - while (cont) { - Object obj = ois.readObject(); - if (obj != null) - pairArrayList.add((SerializablePair) obj); - else - cont = false; - } - - readPerstistanceEntries = true; - } catch (FileNotFoundException e) { - Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); - } catch (EOFException e) { - Log_OC.d(TAG, "Failed with EOFException while reading persistence file"); - readPerstistanceEntries = true; - } catch (IOException e) { - Log_OC.d(TAG, "Failed with IOException while reading persistence file"); - } catch (ClassNotFoundException e) { - Log_OC.d(TAG, "Failed with ClassNotFound while reading persistence file"); - } finally { - try { - if (fis != null) { - fis.close(); - } - } catch (IOException e) { - Log_OC.d(TAG, "Failed with closing FIS"); - } - } - - } - - - if (readPerstistanceEntries && pairArrayList.size() > 0) { - for (int i = 0; i < pairArrayList.size(); i++) { - SyncedFolder syncFolder = pairArrayList.get(i).getKey(); - for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { - if (syncedFolder.getId() == pairArrayList.get(i).getKey().getId()) { - syncFolder = syncedFolder; - break; - } - } - - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncFolder, fileFilter); - observer.setRootEntry(pairArrayList.get(i).getValue()); - observer.addListener(new FileAlterationMagicListener(syncFolder)); - monitor.addObserver(observer); - } - } else { for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { if (syncedFolder.isEnabled()) { FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncedFolder, fileFilter); @@ -144,9 +79,8 @@ public boolean accept(File pathname) { monitor.addObserver(observer); } } - } + //} - syncToDisk(false); try { monitor.start(); @@ -161,60 +95,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { return Service.START_NOT_STICKY; } - public void syncToDisk(boolean destructive) { - pairArrayList = new CopyOnWriteArrayList<>(); - for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { - FileAlterationMagicObserver fileAlterationMagicObserver = - (FileAlterationMagicObserver) fileAlterationObserver; - pairArrayList.add(new SerializablePair(fileAlterationMagicObserver.getSyncedFolder(), - fileAlterationMagicObserver.getRootEntry())); - } - - if (pairArrayList.size() > 0) { - try { - File newFile = new File(file.getAbsolutePath()); - - if (!newFile.exists()) { - newFile.createNewFile(); - } - FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath()), false); - ObjectOutputStream os = new ObjectOutputStream(fos); - for (int i = 0; i < pairArrayList.size(); i++) { - os.writeObject(pairArrayList.get(i)); - } - os.close(); - - if (fos != null) { - fos.close(); - } - - } catch (FileNotFoundException e) { - Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); - } catch (IOException e) { - Log_OC.d(TAG, "Failed writing to nc_persisten file via IOException"); - } - - } else { - if (file.exists()) { - FileUtils.deleteQuietly(file); - } - } - - if (destructive) { - monitor.removeObserver(null); - try { - monitor.stop(); - } catch (Exception e) { - Log_OC.d(TAG, "Failed in stopping monitor"); - } - } - } - - @Override - public void onDestroy() { - syncToDisk(true); - } - /** * Restart oberver if it is enabled * If syncedFolder exists already, use it, otherwise create new observer @@ -254,8 +134,6 @@ public void restartObserver(SyncedFolder syncedFolder) { monitor.addObserver(fileAlterationMagicObserver); } - syncToDisk(false); - } @Override From bd9a12ae005d91adc97dedae81c994d7187b9608 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 14 Feb 2017 13:25:31 +0100 Subject: [PATCH 059/138] Persistent upload magic --- .../android/files/services/FileUploader.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index d797c1d20b1d..88888f7bd186 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -27,6 +27,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; +import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; @@ -108,6 +109,8 @@ public class FileUploader extends Service public static final String KEY_REMOTE_FILE = "REMOTE_FILE"; public static final String KEY_MIME_TYPE = "MIME_TYPE"; + private Notification notification; + /** * Call this Service with only this Intent key if all pending uploads are to be retried. */ @@ -348,6 +351,11 @@ public void onCreate() { mUploadsStorageManager = new UploadsStorageManager(getContentResolver(), getApplicationContext()); + notification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). + getResources().getString(R.string.app_name)) + .setContentText("Uploading...") + .build(); + int failedCounter = mUploadsStorageManager.failInProgressUploads( UploadResult.SERVICE_INTERRUPTED // Add UploadResult.KILLED? ); @@ -401,6 +409,8 @@ public void onDestroy() { public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command with id " + startId); + startForeground(411, notification); + boolean retry = intent.getBooleanExtra(KEY_RETRY, false); AbstractList requestedUploads = new Vector(); @@ -845,6 +855,7 @@ private String buildRemoteName(String accountName, String remotePath) { } + /** * Upload worker. Performs the pending uploads in the order they were * requested. @@ -877,6 +888,7 @@ public void handleMessage(Message msg) { } Log_OC.d(TAG, "Stopping command after id " + msg.arg1); mService.stopSelf(msg.arg1); + } } From 172da075a3dd76ab9268eb13780e4bdcf996600e Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 14 Feb 2017 14:38:13 +0100 Subject: [PATCH 060/138] Change content text for notification --- src/com/owncloud/android/files/services/FileUploader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 88888f7bd186..6d595307cb29 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -353,7 +353,7 @@ public void onCreate() { notification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). getResources().getString(R.string.app_name)) - .setContentText("Uploading...") + .setContentText("Upload service ready") .build(); int failedCounter = mUploadsStorageManager.failInProgressUploads( From a568b5dd792a72cd93444105e261332de68ebbdd Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 14 Feb 2017 16:11:47 +0100 Subject: [PATCH 061/138] Remove permanent marker --- src/com/owncloud/android/files/services/FileUploader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 6d595307cb29..9a05e5df485a 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -887,6 +887,7 @@ public void handleMessage(Message msg) { } } Log_OC.d(TAG, "Stopping command after id " + msg.arg1); + mService.stopForeground(true); mService.stopSelf(msg.arg1); } From 0ee60c55290249c04307c7621f3bc9b405d4ebcf Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 15 Feb 2017 09:12:02 +0100 Subject: [PATCH 062/138] Update for codacy warnings --- .../android/services/FileAlterationMagicListener.java | 2 +- .../services/observer/FileAlterationMagicObserver.java | 4 +++- .../services/observer/SyncedFolderObserverService.java | 5 ----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 6b6a18e5c058..dade5c1252c7 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -96,7 +96,7 @@ public void onFileCreate(final File file) { Long dateFolder = file.lastModified(); final Locale current = context.getResources().getConfiguration().locale; - if (mimetypeString.equalsIgnoreCase("image/jpeg") || mimetypeString.equals("image/tiff")) { + if ("image/jpeg".equalsIgnoreCase(mimetypeString) || "image/tiff".equalsIgnoreCase(mimetypeString)) { try { ExifInterface exifInterface = new ExifInterface(file.getAbsolutePath()); if (!TextUtils.isEmpty(exifInterface.getAttribute(ExifInterface.TAG_DATETIME))) { diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index 760abc12477f..dc1d871f90ac 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -59,7 +59,7 @@ public class FileAlterationMagicObserver extends FileAlterationObserver implemen private Comparator comparator; private SyncedFolder syncedFolder; - static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; + private static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; public FileAlterationMagicObserver(SyncedFolder syncedFolder, FileFilter fileFilter) { @@ -144,6 +144,7 @@ public Iterable getListeners() { * */ public void initialize() { + // does nothing - hack the monitor } @@ -165,6 +166,7 @@ public void init() throws Exception { * @throws Exception if an error occurs */ public void destroy() throws Exception { + // does nothing } /** diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 9f825fd49fb5..32c957bed56b 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -28,7 +28,6 @@ import android.os.IBinder; import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.SerializablePair; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; @@ -37,11 +36,9 @@ import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; -import org.apache.commons.io.monitor.FileEntry; import java.io.File; import java.io.FileFilter; -import java.util.concurrent.CopyOnWriteArrayList; public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; @@ -49,8 +46,6 @@ public class SyncedFolderObserverService extends Service { private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; - private CopyOnWriteArrayList> pairArrayList = new CopyOnWriteArrayList<>(); - private File file; @Override public void onCreate() { From 5c3cd5f6f8841f0377c4144eb6e52ed4d8cc1048 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 15 Feb 2017 09:22:00 +0100 Subject: [PATCH 063/138] Remove content text --- .../owncloud/android/files/services/FileDownloader.java | 9 +++++++++ .../owncloud/android/files/services/FileUploader.java | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index 0c0d0e427e9a..4df2ed3fe3e9 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -23,6 +23,7 @@ import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; +import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; @@ -96,6 +97,7 @@ public class FileDownloader extends Service private NotificationCompat.Builder mNotificationBuilder; private int mLastPercent; + private Notification notification; public static String getDownloadAddedMessage() { return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; @@ -120,6 +122,10 @@ public void onCreate() { mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); + notification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). + getResources().getString(R.string.app_name)) + .build(); + // add AccountsUpdatedListener AccountManager am = AccountManager.get(getApplicationContext()); am.addOnAccountsUpdatedListener(this, null, false); @@ -156,6 +162,8 @@ public void onDestroy() { public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command with id " + startId); + startForeground(412, notification); + if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_FILE) ) { @@ -383,6 +391,7 @@ public void handleMessage(Message msg) { } } Log_OC.d(TAG, "Stopping after command with id " + msg.arg1); + mService.stopForeground(true); mService.stopSelf(msg.arg1); } } diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 9a05e5df485a..02712d291a36 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -353,7 +353,6 @@ public void onCreate() { notification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). getResources().getString(R.string.app_name)) - .setContentText("Upload service ready") .build(); int failedCounter = mUploadsStorageManager.failInProgressUploads( From 91c28ee158f4a375927673ba09cd06f49308ebfc Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 15 Feb 2017 11:24:29 +0100 Subject: [PATCH 064/138] Enable auto upload on Android 6+ only :-/ --- .../android/files/InstantUploadBroadcastReceiver.java | 2 +- src/com/owncloud/android/ui/activity/DrawerActivity.java | 4 ++-- src/com/owncloud/android/ui/activity/FileDisplayActivity.java | 2 +- src/com/owncloud/android/ui/activity/Preferences.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java index 0f9428c421e3..6796477c5e27 100644 --- a/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java +++ b/src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java @@ -58,7 +58,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { Log_OC.d(TAG, "Received: " + intent.getAction()); if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) { handleNewPictureAction(context, intent); diff --git a/src/com/owncloud/android/ui/activity/DrawerActivity.java b/src/com/owncloud/android/ui/activity/DrawerActivity.java index 107617139d5a..c1109bee9b6b 100644 --- a/src/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/src/com/owncloud/android/ui/activity/DrawerActivity.java @@ -175,8 +175,8 @@ protected void setupDrawer() { setupQuotaElement(); - // show folder sync menu item only for Android 5+ - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + // show folder sync menu item only for Android 6+ + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { mNavigationView.getMenu().removeItem(R.id.nav_folder_sync); } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 51f19ecf1760..6b44875b7593 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -257,7 +257,7 @@ public void onClick(View v) { */ private void upgradeNotificationForInstantUpload() { // check for Android 5+ if legacy instant upload is activated --> disable + show info - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (PreferenceManager.instantPictureUploadEnabled(this) || PreferenceManager.instantPictureUploadEnabled(this))) { diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java index 9db1fdb4aeec..de6bf9d23f92 100644 --- a/src/com/owncloud/android/ui/activity/Preferences.java +++ b/src/com/owncloud/android/ui/activity/Preferences.java @@ -368,8 +368,8 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { mPrefInstantUploadCategory = (PreferenceCategory) findPreference("instant_uploading_category"); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - // Instant upload via preferences on pre pre Lollipop + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + // Instant upload via preferences on pre pre M mPrefInstantUploadPath = findPreference("instant_upload_path"); if (mPrefInstantUploadPath != null) { From ead3c16ec4afbe3f567acb0c2da40cfe290b349d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 15 Feb 2017 20:53:54 +0100 Subject: [PATCH 065/138] Try to fix Tobias crash --- src/com/owncloud/android/MainApp.java | 8 +------- .../owncloud/android/datamodel/SyncedFolderProvider.java | 6 +----- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index c9b1eddefd77..641dc99b79c2 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -121,7 +121,6 @@ public void onCreate() { List syncedFolderList = mProvider.getSyncedFolders(); Map, Pair> syncedFolders = new HashMap<>(); ArrayList ids = new ArrayList<>(); - ArrayList syncedFolderArrayList = new ArrayList<>(); for (SyncedFolder syncedFolder : syncedFolderList) { Pair checkPair = new Pair(syncedFolder.getAccount(), syncedFolder.getLocalPath()); if (syncedFolders.containsKey(checkPair)) { @@ -137,14 +136,9 @@ public void onCreate() { ids.add(pair.first); } - for (SyncedFolder syncedFolder : syncedFolderList) { - if (!ids.contains(syncedFolder.getId())) { - syncedFolderArrayList.add(syncedFolder); - } - } if (ids.size() > 0) { - mProvider.deleteSyncFolders(mContext, syncedFolderArrayList, ids); + mProvider.deleteOtherSyncedFolders(mContext, ids); } else { PreferenceManager.getDefaultSharedPreferences(mContext).edit().putBoolean("legacyClean", true).apply(); } diff --git a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java index a288126cd784..b37c9ee78132 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -188,7 +188,7 @@ public SyncedFolder findByLocalPath(String localPath) { } - public int deleteSyncFolders(Context context, ArrayList syncedFolders, ArrayList ids) { + public int deleteOtherSyncedFolders(Context context, ArrayList ids) { int result = mContentResolver.delete( @@ -198,10 +198,6 @@ public int deleteSyncFolders(Context context, ArrayList syncedFold ); if (result > 0) { - for (SyncedFolder syncedFolder : syncedFolders) { - notifyFolderSyncObservers(syncedFolder); - } - if (context != null) { PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("legacyClean", true).apply(); } From 16da98099b5a1d271c2d43e6be3323aa0b14d0a5 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 16 Feb 2017 11:38:56 +0100 Subject: [PATCH 066/138] Update stuff for review --- src/com/owncloud/android/MainApp.java | 22 ++++++++++-------- .../files/services/FileDownloader.java | 6 ++--- .../android/files/services/FileUploader.java | 6 ++--- .../services/FileAlterationMagicListener.java | 23 ++++++++++--------- .../observer/FileAlterationMagicObserver.java | 8 +++++-- .../observer/SyncedFolderObserverService.java | 6 ++--- .../ui/activity/FileDisplayActivity.java | 2 +- 7 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 641dc99b79c2..58afb3379ac6 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -114,31 +114,33 @@ public void onCreate() { Log_OC.d("Debug", "start logging"); } - // clean broken synced folder entries + // previous versions of application created broken entries in the syncedfolderprovider + // database, and this cleans all that and leaves 1 (newest) entry per synced folder + if (!PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("legacyClean", false)) { - SyncedFolderProvider mProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); + SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); - List syncedFolderList = mProvider.getSyncedFolders(); - Map, Pair> syncedFolders = new HashMap<>(); + List syncedFolderList = syncedFolderProvider.getSyncedFolders(); + Map, Long> syncedFolders = new HashMap<>(); ArrayList ids = new ArrayList<>(); for (SyncedFolder syncedFolder : syncedFolderList) { Pair checkPair = new Pair(syncedFolder.getAccount(), syncedFolder.getLocalPath()); if (syncedFolders.containsKey(checkPair)) { - if (syncedFolder.getId() > syncedFolders.get(checkPair).first) { - syncedFolders.put(checkPair, new Pair(syncedFolder.getId(), true)); + if (syncedFolder.getId() > syncedFolders.get(checkPair)) { + syncedFolders.put(checkPair, syncedFolder.getId()); } } else { - syncedFolders.put(checkPair, new Pair(syncedFolder.getId(), false)); + syncedFolders.put(checkPair, syncedFolder.getId()); } } - for (Pair pair : syncedFolders.values()) { - ids.add(pair.first); + for (Long idValue : syncedFolders.values()) { + ids.add(idValue); } if (ids.size() > 0) { - mProvider.deleteOtherSyncedFolders(mContext, ids); + syncedFolderProvider.deleteOtherSyncedFolders(mContext, ids); } else { PreferenceManager.getDefaultSharedPreferences(mContext).edit().putBoolean("legacyClean", true).apply(); } diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index 4df2ed3fe3e9..63f9f15a7b6b 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -97,7 +97,7 @@ public class FileDownloader extends Service private NotificationCompat.Builder mNotificationBuilder; private int mLastPercent; - private Notification notification; + private Notification mNotification; public static String getDownloadAddedMessage() { return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; @@ -122,7 +122,7 @@ public void onCreate() { mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); - notification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). + mNotification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). getResources().getString(R.string.app_name)) .build(); @@ -162,7 +162,7 @@ public void onDestroy() { public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command with id " + startId); - startForeground(412, notification); + startForeground(412, mNotification); if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_FILE) diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 02712d291a36..d95218d68cff 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -109,7 +109,7 @@ public class FileUploader extends Service public static final String KEY_REMOTE_FILE = "REMOTE_FILE"; public static final String KEY_MIME_TYPE = "MIME_TYPE"; - private Notification notification; + private Notification mNotification; /** * Call this Service with only this Intent key if all pending uploads are to be retried. @@ -351,7 +351,7 @@ public void onCreate() { mUploadsStorageManager = new UploadsStorageManager(getContentResolver(), getApplicationContext()); - notification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). + mNotification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). getResources().getString(R.string.app_name)) .build(); @@ -408,7 +408,7 @@ public void onDestroy() { public int onStartCommand(Intent intent, int flags, int startId) { Log_OC.d(TAG, "Starting command with id " + startId); - startForeground(411, notification); + startForeground(411, mNotification); boolean retry = intent.getBooleanExtra(KEY_RETRY, false); AbstractList requestedUploads = new Vector(); diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index dade5c1252c7..99defb9f02ca 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -93,19 +93,19 @@ public void onFileCreate(final File file) { if (file != null) { String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath()); - Long dateFolder = file.lastModified(); - final Locale current = context.getResources().getConfiguration().locale; + Long lastModificationTime = file.lastModified(); + final Locale currentLocale = context.getResources().getConfiguration().locale; if ("image/jpeg".equalsIgnoreCase(mimetypeString) || "image/tiff".equalsIgnoreCase(mimetypeString)) { try { ExifInterface exifInterface = new ExifInterface(file.getAbsolutePath()); - if (!TextUtils.isEmpty(exifInterface.getAttribute(ExifInterface.TAG_DATETIME))) { - String exifDate = exifInterface.getAttribute(ExifInterface.TAG_DATETIME); + String exifDate = exifInterface.getAttribute(ExifInterface.TAG_DATETIME); + if (!TextUtils.isEmpty(exifDate)) { ParsePosition pos = new ParsePosition(0); - SimpleDateFormat sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", current); + SimpleDateFormat sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale); sFormatter.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID())); - Date datetime = sFormatter.parse(exifDate, pos); - dateFolder = datetime.getTime(); + Date dateTime = sFormatter.parse(exifDate, pos); + lastModificationTime = dateTime.getTime(); } } catch (IOException e) { @@ -114,7 +114,7 @@ public void onFileCreate(final File file) { } - final Long finalDateFolder = dateFolder; + final Long finalLastModificationTime = lastModificationTime; final Runnable runnable = new Runnable() { @Override @@ -122,9 +122,9 @@ public void run() { PersistableBundle bundle = new PersistableBundle(); bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( - current, + currentLocale, syncedFolder.getRemotePath(), file.getName(), - finalDateFolder, + finalLastModificationTime, syncedFolder.getSubfolderByDate())); bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); @@ -137,7 +137,8 @@ public void run() { new ComponentName(context, SyncedFolderJobService.class)) .setRequiresCharging(syncedFolder.getChargingOnly()) .setMinimumLatency(10000) - .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY) + .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : + JobInfo.NETWORK_TYPE_ANY) .setExtras(bundle) .setPersisted(true) .build(); diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index dc1d871f90ac..1639d4c98da3 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -14,8 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Modified a bit by Mario Danic + * Original source code: + * https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/monitor/FileAlterationObserver.java + * + * Modified by Mario Danic * Changes are Copyright (C) 2017 Mario Danic + * Copyright (C) 2017 Nextcloud GmbH * * Those changes are under the following licence: * @@ -170,7 +174,7 @@ public void destroy() throws Exception { } /** - * Check whether the file and its chlidren have been created, modified or deleted. + * Check whether the file and its children have been created, modified or deleted. */ public void checkAndNotify() { diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 32c957bed56b..88d8a8390d66 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -42,14 +42,14 @@ public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; - private SyncedFolderProvider mProvider; + private SyncedFolderProvider syncedFolderProvider; private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; @Override public void onCreate() { - mProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); + syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); monitor = new FileAlterationMonitor(); fileFilter = new FileFilter() { @@ -60,7 +60,7 @@ public boolean accept(File pathname) { }; - for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) { + for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) { if (syncedFolder.isEnabled()) { FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncedFolder, fileFilter); diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 6b44875b7593..308634e18560 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -256,7 +256,7 @@ public void onClick(View v) { * Opens a pop up info for the new instant upload and disabled the old instant upload. */ private void upgradeNotificationForInstantUpload() { - // check for Android 5+ if legacy instant upload is activated --> disable + show info + // check for Android 6+ if legacy instant upload is activated --> disable + show info if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (PreferenceManager.instantPictureUploadEnabled(this) || PreferenceManager.instantPictureUploadEnabled(this))) { From 137432068b9764936310ed585a394bb12b08dc52 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sat, 18 Feb 2017 03:38:25 +0100 Subject: [PATCH 067/138] =?UTF-8?q?Don=E2=80=99t=20add=20observer=20if=20i?= =?UTF-8?q?t=20fails=20to=20init?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../observer/SyncedFolderObserverService.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 88d8a8390d66..90da7d50fedf 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -60,21 +60,20 @@ public boolean accept(File pathname) { }; - for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) { - if (syncedFolder.isEnabled()) { - FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncedFolder, fileFilter); - - try { - observer.init(); - } catch (Exception e) { - Log_OC.d(TAG, "Failed getting an observer to intialize"); - } + for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) { + if (syncedFolder.isEnabled()) { + FileAlterationMagicObserver observer = new FileAlterationMagicObserver(syncedFolder, fileFilter); + try { + observer.init(); observer.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(observer); + } catch (Exception e) { + Log_OC.d(TAG, "Failed getting an observer to intialize"); } + } - //} + } try { @@ -118,15 +117,15 @@ public void restartObserver(SyncedFolder syncedFolder) { } if (!found && syncedFolder.isEnabled()) { - fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); try { + fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); fileAlterationMagicObserver.init(); + fileAlterationMagicObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(fileAlterationMagicObserver); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); } - fileAlterationMagicObserver.addListener(new FileAlterationMagicListener(syncedFolder)); - monitor.addObserver(fileAlterationMagicObserver); } } From c867b54ee37b7c002876c6b749a797a3162ec94a Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sat, 18 Feb 2017 15:35:50 +0100 Subject: [PATCH 068/138] Update codacy --- src/com/owncloud/android/MainApp.java | 68 ++++++++++--------- .../datamodel/SyncedFolderProvider.java | 6 +- .../observer/FileAlterationMagicObserver.java | 4 +- .../observer/SyncedFolderObserverService.java | 4 +- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 58afb3379ac6..30c5a1ea7497 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -114,38 +114,8 @@ public void onCreate() { Log_OC.d("Debug", "start logging"); } - // previous versions of application created broken entries in the syncedfolderprovider - // database, and this cleans all that and leaves 1 (newest) entry per synced folder - - if (!PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("legacyClean", false)) { - SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); - - List syncedFolderList = syncedFolderProvider.getSyncedFolders(); - Map, Long> syncedFolders = new HashMap<>(); - ArrayList ids = new ArrayList<>(); - for (SyncedFolder syncedFolder : syncedFolderList) { - Pair checkPair = new Pair(syncedFolder.getAccount(), syncedFolder.getLocalPath()); - if (syncedFolders.containsKey(checkPair)) { - if (syncedFolder.getId() > syncedFolders.get(checkPair)) { - syncedFolders.put(checkPair, syncedFolder.getId()); - } - } else { - syncedFolders.put(checkPair, syncedFolder.getId()); - } - } - - for (Long idValue : syncedFolders.values()) { - ids.add(idValue); - } - - - if (ids.size() > 0) { - syncedFolderProvider.deleteOtherSyncedFolders(mContext, ids); - } else { - PreferenceManager.getDefaultSharedPreferences(mContext).edit().putBoolean("legacyClean", true).apply(); - } - } - + cleanOldEntries(); + Log_OC.d("SyncedFolderObserverService", "Start service SyncedFolderObserverService"); Intent i = new Intent(this, SyncedFolderObserverService.class); startService(i); @@ -296,6 +266,40 @@ public static String getUserAgent() { return userAgent; } + private void cleanOldEntries() { + // previous versions of application created broken entries in the syncedfolderprovider + // database, and this cleans all that and leaves 1 (newest) entry per synced folder + + if (!PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("legacyClean", false)) { + SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); + + List syncedFolderList = syncedFolderProvider.getSyncedFolders(); + Map, Long> syncedFolders = new HashMap<>(); + ArrayList ids = new ArrayList<>(); + for (SyncedFolder syncedFolder : syncedFolderList) { + Pair checkPair = new Pair(syncedFolder.getAccount(), syncedFolder.getLocalPath()); + if (syncedFolders.containsKey(checkPair)) { + if (syncedFolder.getId() > syncedFolders.get(checkPair)) { + syncedFolders.put(checkPair, syncedFolder.getId()); + } + } else { + syncedFolders.put(checkPair, syncedFolder.getId()); + } + } + + for (Long idValue : syncedFolders.values()) { + ids.add(idValue); + } + + + if (ids.size() > 0) { + syncedFolderProvider.deleteOtherSyncedFolders(mContext, ids); + } else { + PreferenceManager.getDefaultSharedPreferences(mContext).edit().putBoolean("legacyClean", true).apply(); + } + } + } + /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection syncedFolderObserverServiceConnection = new ServiceConnection() { diff --git a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java index b37c9ee78132..3662638f76a3 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/src/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -197,10 +197,8 @@ public int deleteOtherSyncedFolders(Context context, ArrayList ids) { new String[]{String.valueOf(ids)} ); - if (result > 0) { - if (context != null) { - PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("legacyClean", true).apply(); - } + if (result > 0 && context != null) { + PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("legacyClean", true).apply(); } return result; diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index 1639d4c98da3..f389c16cae7a 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -189,9 +189,7 @@ public void checkAndNotify() { checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile)); } else if (rootEntry.isExists()) { checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); - } else { - // Didn't exist and still doesn't - } + } // else didn't exist and still doesn't /* fire onStop() */ for (final FileAlterationListener listener : listeners) { diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 90da7d50fedf..3688f0bb5ff3 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -42,14 +42,14 @@ public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; - private SyncedFolderProvider syncedFolderProvider; private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; @Override public void onCreate() { - syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); + SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext(). + getContentResolver()); monitor = new FileAlterationMonitor(); fileFilter = new FileFilter() { From 4ef5bc8c80f7297447e1448ef5122ab1c3282ee3 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Sun, 19 Feb 2017 18:53:35 +0100 Subject: [PATCH 069/138] Wait on shutdown --- AndroidManifest.xml | 7 ++ .../services/FileAlterationMagicListener.java | 26 +++++-- .../android/services/ShutdownReceiver.java | 42 ++++++++++ .../services/SyncedFolderJobService.java | 76 ++++++++++--------- .../observer/FileAlterationMagicObserver.java | 11 ++- .../observer/SyncedFolderObserverService.java | 17 ++++- 6 files changed, 135 insertions(+), 44 deletions(-) create mode 100644 src/com/owncloud/android/services/ShutdownReceiver.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e8c1a2842147..c3fa970d5707 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -244,6 +244,13 @@ + + + + + + + diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 99defb9f02ca..26a4918b7097 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -40,10 +40,10 @@ import java.io.IOException; import java.text.ParsePosition; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; +import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.TimeZone; /** @@ -59,7 +59,9 @@ public class FileAlterationMagicListener implements FileAlterationListener { private SyncedFolder syncedFolder; private Handler handler = new Handler(); - private Map fileRunnable = new HashMap<>(); + //private Map fileRunnable = new HashMap<>(); + + private List filesList = new ArrayList<>(); public FileAlterationMagicListener(SyncedFolder syncedFolder) { super(); @@ -91,6 +93,7 @@ public void onDirectoryDelete(File directory) { @Override public void onFileCreate(final File file) { if (file != null) { + filesList.add(file.getAbsolutePath()); String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath()); Long lastModificationTime = file.lastModified(); @@ -148,34 +151,41 @@ public void run() { Log_OC.d(TAG, "Job failed to start: " + result); } - fileRunnable.remove(file.getAbsolutePath()); + //fileRunnable.remove(file.getAbsolutePath()); + filesList.remove(file.getAbsolutePath()); } }; - fileRunnable.put(file.getAbsolutePath(), runnable); - handler.postDelayed(runnable, 1500); + //fileRunnable.put(file.getAbsolutePath(), runnable); + handler.post(runnable); } } @Override public void onFileChange(File file) { + /* Left here for later if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 1500); - } + }*/ } @Override public void onFileDelete(File file) { + /* Left here for later if (fileRunnable.containsKey(file.getAbsolutePath())) { handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); fileRunnable.remove(file.getAbsolutePath()); - } + }*/ } @Override public void onStop(FileAlterationObserver observer) { // This method is intentionally empty } + + public int getActiveTasksCount() { + return filesList.size(); + } } diff --git a/src/com/owncloud/android/services/ShutdownReceiver.java b/src/com/owncloud/android/services/ShutdownReceiver.java new file mode 100644 index 000000000000..4413510bdf63 --- /dev/null +++ b/src/com/owncloud/android/services/ShutdownReceiver.java @@ -0,0 +1,42 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * Copyright (C) 2017 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.services; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.owncloud.android.MainApp; + +/** + * Handles shutdown procedure - basically just waits a little bit for all jobs to finish + */ + +public class ShutdownReceiver extends BroadcastReceiver { + private static final String TAG = "ShutdownReceiver"; + + @Override + public void onReceive(final Context context, final Intent intent) { + if (MainApp.getSyncedFolderObserverService() != null) { + MainApp.getSyncedFolderObserverService().onDestroy(); + } + } +} diff --git a/src/com/owncloud/android/services/SyncedFolderJobService.java b/src/com/owncloud/android/services/SyncedFolderJobService.java index 3a27c73680f7..e74691c2642d 100644 --- a/src/com/owncloud/android/services/SyncedFolderJobService.java +++ b/src/com/owncloud/android/services/SyncedFolderJobService.java @@ -1,22 +1,22 @@ /** - * Nextcloud Android client application + * Nextcloud Android client application * - * @author Tobias Kaminsky - * Copyright (C) 2016 Tobias Kaminsky - * Copyright (C) 2016 Nextcloud - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this program. If not, see . + * @author Tobias Kaminsky + * Copyright (C) 2016 Tobias Kaminsky + * Copyright (C) 2016 Nextcloud + *

+ * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + *

+ * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . */ package com.owncloud.android.services; @@ -28,6 +28,7 @@ import android.content.Context; import android.content.Intent; import android.os.Build; +import android.os.Handler; import android.os.PersistableBundle; import com.owncloud.android.MainApp; @@ -55,33 +56,40 @@ public int onStartCommand(Intent intent, int flags, int startId) { @Override public boolean onStartJob(JobParameters params) { - Context context = MainApp.getAppContext(); + final Context context = MainApp.getAppContext(); PersistableBundle bundle = params.getExtras(); - String filePath = bundle.getString(LOCAL_PATH); - String remotePath = bundle.getString(REMOTE_PATH); - Account account = AccountUtils.getOwnCloudAccountByName(context, bundle.getString(ACCOUNT)); - Integer uploadBehaviour = bundle.getInt(UPLOAD_BEHAVIOUR); + final String filePath = bundle.getString(LOCAL_PATH); + final String remotePath = bundle.getString(REMOTE_PATH); + final Account account = AccountUtils.getOwnCloudAccountByName(context, bundle.getString(ACCOUNT)); + final Integer uploadBehaviour = bundle.getInt(UPLOAD_BEHAVIOUR); Log_OC.d(TAG, "startJob: " + params.getJobId() + ", filePath: " + filePath); File file = new File(filePath); + Handler handler = new Handler(); + // File can be deleted between job generation and job execution. If file does not exist, just ignore it if (file.exists()) { - String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(file.getAbsolutePath()); + final String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(file.getAbsolutePath()); - FileUploader.UploadRequester requester = new FileUploader.UploadRequester(); + final FileUploader.UploadRequester requester = new FileUploader.UploadRequester(); - requester.uploadNewFile( - context, - account, - filePath, - remotePath, - uploadBehaviour, - mimeType, - true, // create parent folder if not existent - UploadFileOperation.CREATED_AS_INSTANT_PICTURE - ); + handler.postDelayed(new Runnable() { + @Override + public void run() { + requester.uploadNewFile( + context, + account, + filePath, + remotePath, + uploadBehaviour, + mimeType, + true, // create parent folder if not existent + UploadFileOperation.CREATED_AS_INSTANT_PICTURE + ); + } + }, 5000); } return false; } diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index f389c16cae7a..93892f764a8e 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -38,7 +38,10 @@ */ package com.owncloud.android.services.observer; +import android.os.SystemClock; + import com.owncloud.android.datamodel.SyncedFolder; +import com.owncloud.android.services.FileAlterationMagicListener; import org.apache.commons.io.FileUtils; import org.apache.commons.io.comparator.NameFileComparator; @@ -170,7 +173,13 @@ public void init() throws Exception { * @throws Exception if an error occurs */ public void destroy() throws Exception { - // does nothing + while (getListeners().iterator().hasNext()) { + FileAlterationMagicListener fileAlterationListener = (FileAlterationMagicListener) + getListeners().iterator().next(); + while (fileAlterationListener.getActiveTasksCount() > 0) { + SystemClock.sleep(250); + } + } } /** diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 3688f0bb5ff3..a8324055f8da 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -26,6 +26,7 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; +import android.util.Log; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; @@ -84,6 +85,21 @@ public boolean accept(File pathname) { } + @Override + public void onDestroy() { + super.onDestroy(); + Log.d("MARIO", "DESTROY"); + for(FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { + FileAlterationMagicObserver fileAlterationMagicObserver = (FileAlterationMagicObserver) + fileAlterationObserver; + try { + fileAlterationMagicObserver.destroy(); + } catch (Exception e) { + Log_OC.d(TAG, "Something went very wrong on trying to destroy observers"); + } + } + } + @Override public int onStartCommand(Intent intent, int flags, int startId) { return Service.START_NOT_STICKY; @@ -121,7 +137,6 @@ public void restartObserver(SyncedFolder syncedFolder) { fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); fileAlterationMagicObserver.init(); fileAlterationMagicObserver.addListener(new FileAlterationMagicListener(syncedFolder)); - monitor.addObserver(fileAlterationMagicObserver); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); } From 2d584ad9a791f6b7b0bd401239543aafd1c601eb Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 20 Feb 2017 19:04:12 +0100 Subject: [PATCH 070/138] Fix path for files --- .../services/observer/SyncedFolderObserverService.java | 2 -- src/com/owncloud/android/utils/FileStorageUtils.java | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index a8324055f8da..95a054f5b38b 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -26,7 +26,6 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import android.util.Log; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; @@ -88,7 +87,6 @@ public boolean accept(File pathname) { @Override public void onDestroy() { super.onDestroy(); - Log.d("MARIO", "DESTROY"); for(FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { FileAlterationMagicObserver fileAlterationMagicObserver = (FileAlterationMagicObserver) fileAlterationObserver; diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java index c31a67112a6f..b9af0e42e95f 100644 --- a/src/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/com/owncloud/android/utils/FileStorageUtils.java @@ -167,7 +167,7 @@ public static String getInstantUploadFilePath(Locale current, String remotePath, if (subfolderByDate) { subPath = getSubpathFromDate(dateTaken, current); } - return remotePath + OCFile.PATH_SEPARATOR + subPath + (fileName == null ? "" : fileName); + return remotePath + subPath + (fileName == null ? "" : fileName); } public static String getInstantUploadFilePath(String remotePath, String fileName, long dateTaken, @@ -176,7 +176,7 @@ public static String getInstantUploadFilePath(String remotePath, String fileName if (subfolderByDate) { subPath = getSubpathFromDate(dateTaken); } - return remotePath + OCFile.PATH_SEPARATOR + subPath + (fileName == null ? "" : fileName); + return remotePath + subPath + (fileName == null ? "" : fileName); } @@ -194,7 +194,7 @@ public static String getInstantVideoUploadFilePath(Context context, String fileN if (com.owncloud.android.db.PreferenceManager.instantVideoUploadPathUseSubfolders(context)) { subPath = getSubpathFromDate(dateTaken); } - return uploadVideoPath + OCFile.PATH_SEPARATOR + subPath + return uploadVideoPath + subPath + (fileName == null ? "" : fileName); } From 7daf7a110681819ceae473409c8198ec918b52d6 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 20 Feb 2017 19:46:57 +0100 Subject: [PATCH 071/138] Clean up iterator --- .../services/observer/FileAlterationMagicObserver.java | 8 +++++--- .../services/observer/SyncedFolderObserverService.java | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index 93892f764a8e..e97c0638d9ce 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -54,6 +54,7 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -173,12 +174,13 @@ public void init() throws Exception { * @throws Exception if an error occurs */ public void destroy() throws Exception { - while (getListeners().iterator().hasNext()) { - FileAlterationMagicListener fileAlterationListener = (FileAlterationMagicListener) - getListeners().iterator().next(); + Iterator iterator = getListeners().iterator(); + while (iterator.hasNext()) { + FileAlterationMagicListener fileAlterationListener = (FileAlterationMagicListener) iterator.next(); while (fileAlterationListener.getActiveTasksCount() > 0) { SystemClock.sleep(250); } + } } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 95a054f5b38b..a38a901e3159 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -69,7 +69,7 @@ public boolean accept(File pathname) { observer.addListener(new FileAlterationMagicListener(syncedFolder)); monitor.addObserver(observer); } catch (Exception e) { - Log_OC.d(TAG, "Failed getting an observer to intialize"); + Log_OC.d(TAG, "Failed getting an observer to intialize " + e); } } From 6d98473654e7dfc5a40200433081734f991246b6 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 20 Feb 2017 19:58:47 +0100 Subject: [PATCH 072/138] Revert things to how they were --- .../services/FileAlterationMagicListener.java | 2 +- .../services/SyncedFolderJobService.java | 27 +++++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 26a4918b7097..ce9805c88781 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -157,7 +157,7 @@ public void run() { }; //fileRunnable.put(file.getAbsolutePath(), runnable); - handler.post(runnable); + handler.postDelayed(runnable, 1500); } } diff --git a/src/com/owncloud/android/services/SyncedFolderJobService.java b/src/com/owncloud/android/services/SyncedFolderJobService.java index e74691c2642d..3c6e4f79d0a1 100644 --- a/src/com/owncloud/android/services/SyncedFolderJobService.java +++ b/src/com/owncloud/android/services/SyncedFolderJobService.java @@ -28,7 +28,6 @@ import android.content.Context; import android.content.Intent; import android.os.Build; -import android.os.Handler; import android.os.PersistableBundle; import com.owncloud.android.MainApp; @@ -67,7 +66,6 @@ public boolean onStartJob(JobParameters params) { File file = new File(filePath); - Handler handler = new Handler(); // File can be deleted between job generation and job execution. If file does not exist, just ignore it if (file.exists()) { @@ -75,21 +73,16 @@ public boolean onStartJob(JobParameters params) { final FileUploader.UploadRequester requester = new FileUploader.UploadRequester(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - requester.uploadNewFile( - context, - account, - filePath, - remotePath, - uploadBehaviour, - mimeType, - true, // create parent folder if not existent - UploadFileOperation.CREATED_AS_INSTANT_PICTURE - ); - } - }, 5000); + requester.uploadNewFile( + context, + account, + filePath, + remotePath, + uploadBehaviour, + mimeType, + true, // create parent folder if not existent + UploadFileOperation.CREATED_AS_INSTANT_PICTURE + ); } return false; } From 60325485c6d03f4fb87323eba924f4cfaa01e152 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 20 Feb 2017 21:57:26 +0100 Subject: [PATCH 073/138] Some magics --- .../observer/FileAlterationMagicObserver.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index e97c0638d9ce..6a9dd8d98904 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -41,6 +41,7 @@ import android.os.SystemClock; import com.owncloud.android.datamodel.SyncedFolder; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.FileAlterationMagicListener; import org.apache.commons.io.FileUtils; @@ -199,7 +200,18 @@ public void checkAndNotify() { if (rootFile.exists()) { checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile)); } else if (rootEntry.isExists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + try { + // try to init once more + init(); + if (rootEntry.getFile().exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile())); + } else { + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + } + } catch (Exception e) { + Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + } } // else didn't exist and still doesn't /* fire onStop() */ From ebeb520bf85dbbfe066f78f15db809cd3d12fa2c Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Mon, 20 Feb 2017 22:53:57 +0100 Subject: [PATCH 074/138] Fix a tiny bug --- .../android/services/observer/SyncedFolderObserverService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index a38a901e3159..1502a8614011 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -135,6 +135,7 @@ public void restartObserver(SyncedFolder syncedFolder) { fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); fileAlterationMagicObserver.init(); fileAlterationMagicObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(fileAlterationMagicObserver); } catch (Exception e) { Log_OC.d(TAG, "Failed getting an observer to intialize"); } From a333ead38c44aa7b421e283aeb1bb46a99f18600 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 01:50:15 +0100 Subject: [PATCH 075/138] Remove serializable pair --- .../android/datamodel/SerializablePair.java | 66 ------------------- 1 file changed, 66 deletions(-) delete mode 100644 src/com/owncloud/android/datamodel/SerializablePair.java diff --git a/src/com/owncloud/android/datamodel/SerializablePair.java b/src/com/owncloud/android/datamodel/SerializablePair.java deleted file mode 100644 index 4746b1dacfa3..000000000000 --- a/src/com/owncloud/android/datamodel/SerializablePair.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Nextcloud Android client application - * - * @author Mario Danic - * Copyright (C) 2017 Mario Danic - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.datamodel; - -import android.support.v4.util.Pair; - -import org.apache.commons.io.monitor.FileEntry; - -import java.io.IOException; -import java.io.Serializable; - -/** - * Pair that we can serialize - */ - -public class SerializablePair implements Serializable { - private static final long serialVersionUID = -1710182118966395715L; - private transient Pair pair = null; - - public SerializablePair(SyncedFolder key, FileEntry value) { - this.pair = new Pair(key, value); - } - - private void writeObject(java.io.ObjectOutputStream stream) - throws IOException { - stream.writeObject(pair.first); - stream.writeObject(pair.second); - } - - private void readObject(java.io.ObjectInputStream stream) - throws IOException, ClassNotFoundException { - SyncedFolder syncedFolder = (SyncedFolder) stream.readObject(); - FileEntry fileEntry = (FileEntry) stream.readObject(); - pair = new Pair(syncedFolder, fileEntry); - } - - @Override - public String toString() { - return pair.toString(); - } - - public SyncedFolder getKey() { - return (SyncedFolder)this.pair.first; - } - - public FileEntry getValue() { - return (FileEntry)this.pair.second; - } -} From 048b7f7bb3217aa6177687ade1e1e75c4d34b43e Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 11:14:01 +0100 Subject: [PATCH 076/138] Use android-job for scheduling --- build.gradle | 1 + src/com/owncloud/android/MainApp.java | 6 +- .../datamodel/UploadsStorageManager.java | 44 ++++++----- ...lderJobService.java => AutoUploadJob.java} | 43 ++++------- .../services/FileAlterationMagicListener.java | 73 ++++++++----------- .../android/services/NCJobCreator.java | 20 +++++ .../observer/FileAlterationMagicObserver.java | 1 - .../observer/SyncedFolderObserverService.java | 1 + 8 files changed, 92 insertions(+), 97 deletions(-) rename src/com/owncloud/android/services/{SyncedFolderJobService.java => AutoUploadJob.java} (68%) create mode 100644 src/com/owncloud/android/services/NCJobCreator.java diff --git a/build.gradle b/build.gradle index db54a60534fe..429727b38c14 100644 --- a/build.gradle +++ b/build.gradle @@ -49,6 +49,7 @@ dependencies { compile 'com.getbase:floatingactionbutton:1.10.1' compile 'com.google.code.findbugs:annotations:2.0.1' compile group: 'commons-io', name: 'commons-io', version: '2.4' + compile 'com.evernote:android-job:1.1.6' /// dependencies for local unit tests testCompile 'junit:junit:4.12' diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 30c5a1ea7497..fc78e26eecb8 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -34,6 +34,7 @@ import android.preference.PreferenceManager; import android.support.v4.util.Pair; +import com.evernote.android.job.JobManager; import com.owncloud.android.authentication.PassCodeManager; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; @@ -41,6 +42,7 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.services.NCJobCreator; import com.owncloud.android.services.observer.SyncedFolderObserverService; import com.owncloud.android.ui.activity.Preferences; import com.owncloud.android.ui.activity.WhatsNewActivity; @@ -115,7 +117,9 @@ public void onCreate() { } cleanOldEntries(); - + + JobManager.create(this).addJobCreator(new NCJobCreator()); + Log_OC.d("SyncedFolderObserverService", "Start service SyncedFolderObserverService"); Intent i = new Intent(this, SyncedFolderObserverService.class); startService(i); diff --git a/src/com/owncloud/android/datamodel/UploadsStorageManager.java b/src/com/owncloud/android/datamodel/UploadsStorageManager.java index 197adc8ccf00..7580ab595b8c 100644 --- a/src/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/src/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -21,17 +21,17 @@ package com.owncloud.android.datamodel; import android.accounts.Account; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Build; -import android.os.PersistableBundle; import android.support.annotation.RequiresApi; +import com.evernote.android.job.JobManager; +import com.evernote.android.job.JobRequest; +import com.evernote.android.job.util.support.PersistableBundleCompat; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.db.OCUpload; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; @@ -46,6 +46,7 @@ import java.util.Collections; import java.util.List; import java.util.Observable; +import java.util.Set; /** * Database helper for storing list of files to be uploaded, including status @@ -400,22 +401,20 @@ public OCUpload[] getCurrentAndPendingUploads() { @RequiresApi(Build.VERSION_CODES.LOLLIPOP) private List getPendingJobs() { - JobScheduler js = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); + Set jobRequests = JobManager.create(mContext).getAllJobRequests(); Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); ArrayList list = new ArrayList<>(); - if (js != null) { - for (JobInfo ji : js.getAllPendingJobs()) { - PersistableBundle extras = ji.getExtras(); - if (extras.get("account").equals(currentAccount.name)) { - OCUpload upload = new OCUpload(extras.getString("filePath"), - extras.getString("remotePath"), - extras.getString("account")); + for (JobRequest ji : jobRequests) { + PersistableBundleCompat extras = ji.getExtras(); + if (extras.get("account").equals(currentAccount.name)) { + OCUpload upload = new OCUpload(extras.getString("filePath", ""), + extras.getString("remotePath", ""), + extras.getString("account", "")); - list.add(upload); - } + list.add(upload); } } @@ -424,16 +423,15 @@ private List getPendingJobs() { @RequiresApi(Build.VERSION_CODES.LOLLIPOP) public void cancelPendingJob(String accountName, String remotePath){ - JobScheduler js = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - if (js != null) { - for (JobInfo ji : js.getAllPendingJobs()) { - PersistableBundle extras = ji.getExtras(); - if (remotePath.equalsIgnoreCase(extras.getString("remotePath")) && - accountName.equalsIgnoreCase(extras.getString("account"))) { - js.cancel(ji.getId()); - break; - } + JobManager jobManager = JobManager.create(mContext); + Set jobRequests = jobManager.getAllJobRequests(); + + for (JobRequest ji : jobRequests) { + PersistableBundleCompat extras = ji.getExtras(); + if (remotePath.equalsIgnoreCase(extras.getString("remotePath", "")) && + accountName.equalsIgnoreCase(extras.getString("account", ""))) { + jobManager.cancel(ji.getJobId()); + break; } } } diff --git a/src/com/owncloud/android/services/SyncedFolderJobService.java b/src/com/owncloud/android/services/AutoUploadJob.java similarity index 68% rename from src/com/owncloud/android/services/SyncedFolderJobService.java rename to src/com/owncloud/android/services/AutoUploadJob.java index 3c6e4f79d0a1..86c3759f168a 100644 --- a/src/com/owncloud/android/services/SyncedFolderJobService.java +++ b/src/com/owncloud/android/services/AutoUploadJob.java @@ -22,47 +22,37 @@ package com.owncloud.android.services; import android.accounts.Account; -import android.annotation.TargetApi; -import android.app.job.JobParameters; -import android.app.job.JobService; import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.PersistableBundle; +import android.support.annotation.NonNull; +import com.evernote.android.job.Job; +import com.evernote.android.job.util.support.PersistableBundleCompat; import com.owncloud.android.MainApp; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.files.services.FileUploader; -import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.operations.UploadFileOperation; import com.owncloud.android.utils.MimeTypeUtil; import java.io.File; -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class SyncedFolderJobService extends JobService { - private static final String TAG = "SyncedFolderJobService"; +public class AutoUploadJob extends Job { + public static final String TAG = "AutoUploadJob"; - public static final String LOCAL_PATH = "filePath"; + private static final String LOCAL_PATH = "filePath"; public static final String REMOTE_PATH = "remotePath"; public static final String ACCOUNT = "account"; public static final String UPLOAD_BEHAVIOUR = "uploadBehaviour"; + @NonNull @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return START_REDELIVER_INTENT; - } - - @Override - public boolean onStartJob(JobParameters params) { + protected Result onRunJob(Params params) { final Context context = MainApp.getAppContext(); - PersistableBundle bundle = params.getExtras(); - final String filePath = bundle.getString(LOCAL_PATH); - final String remotePath = bundle.getString(REMOTE_PATH); - final Account account = AccountUtils.getOwnCloudAccountByName(context, bundle.getString(ACCOUNT)); - final Integer uploadBehaviour = bundle.getInt(UPLOAD_BEHAVIOUR); + PersistableBundleCompat bundle = params.getExtras(); + final String filePath = bundle.getString(LOCAL_PATH, ""); + final String remotePath = bundle.getString(REMOTE_PATH, ""); + final Account account = AccountUtils.getOwnCloudAccountByName(context, bundle.getString(ACCOUNT, "")); + final Integer uploadBehaviour = bundle.getInt(UPLOAD_BEHAVIOUR, -1); - Log_OC.d(TAG, "startJob: " + params.getJobId() + ", filePath: " + filePath); File file = new File(filePath); @@ -72,7 +62,6 @@ public boolean onStartJob(JobParameters params) { final String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(file.getAbsolutePath()); final FileUploader.UploadRequester requester = new FileUploader.UploadRequester(); - requester.uploadNewFile( context, account, @@ -84,11 +73,7 @@ public boolean onStartJob(JobParameters params) { UploadFileOperation.CREATED_AS_INSTANT_PICTURE ); } - return false; - } - @Override - public boolean onStopJob(JobParameters params) { - return false; + return Result.SUCCESS; } } diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index ce9805c88781..7cf73ec57fc5 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -3,31 +3,30 @@ * * @author Mario Danic * Copyright (C) 2017 Mario Danic - * + *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + *

* You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package com.owncloud.android.services; -import android.app.job.JobInfo; import android.app.job.JobScheduler; -import android.content.ComponentName; import android.content.Context; import android.media.ExifInterface; import android.os.Handler; -import android.os.PersistableBundle; import android.text.TextUtils; +import com.evernote.android.job.JobRequest; +import com.evernote.android.job.util.support.PersistableBundleCompat; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.lib.common.utils.Log_OC; @@ -119,45 +118,33 @@ public void onFileCreate(final File file) { final Long finalLastModificationTime = lastModificationTime; - final Runnable runnable = new Runnable() { - @Override - public void run() { - PersistableBundle bundle = new PersistableBundle(); - bundle.putString(SyncedFolderJobService.LOCAL_PATH, file.getAbsolutePath()); - bundle.putString(SyncedFolderJobService.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( - currentLocale, - syncedFolder.getRemotePath(), file.getName(), - finalLastModificationTime, - syncedFolder.getSubfolderByDate())); - bundle.putString(SyncedFolderJobService.ACCOUNT, syncedFolder.getAccount()); - bundle.putInt(SyncedFolderJobService.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); - - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - - Long date = new Date().getTime(); - JobInfo job = new JobInfo.Builder( - date.intValue(), - new ComponentName(context, SyncedFolderJobService.class)) - .setRequiresCharging(syncedFolder.getChargingOnly()) - .setMinimumLatency(10000) - .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobInfo.NETWORK_TYPE_UNMETERED : - JobInfo.NETWORK_TYPE_ANY) - .setExtras(bundle) - .setPersisted(true) - .build(); - - Integer result = js.schedule(job); - if (result <= 0) { - Log_OC.d(TAG, "Job failed to start: " + result); - } - - //fileRunnable.remove(file.getAbsolutePath()); - filesList.remove(file.getAbsolutePath()); - } - }; + PersistableBundleCompat bundle = new PersistableBundleCompat(); + bundle.putString(AutoUploadJob.LOCAL_PATH, file.getAbsolutePath()); + bundle.putString(AutoUploadJob.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( + currentLocale, + syncedFolder.getRemotePath(), file.getName(), + finalLastModificationTime, + syncedFolder.getSubfolderByDate())); + bundle.putString(AutoUploadJob.ACCOUNT, syncedFolder.getAccount()); + bundle.putInt(AutoUploadJob.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); + + JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); + + int jobId = new JobRequest.Builder(AutoUploadJob.TAG) + .setExecutionWindow(30_000L, 40_000L) + .setRequiresCharging(syncedFolder.getChargingOnly()) + .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobRequest.NetworkType.UNMETERED : + JobRequest.NetworkType.ANY) + .setExtras(bundle) + .setPersisted(true) + .build() + .schedule(); + + //fileRunnable.remove(file.getAbsolutePath()); + filesList.remove(file.getAbsolutePath()); //fileRunnable.put(file.getAbsolutePath(), runnable); - handler.postDelayed(runnable, 1500); + //handler.post(runnable); } } diff --git a/src/com/owncloud/android/services/NCJobCreator.java b/src/com/owncloud/android/services/NCJobCreator.java new file mode 100644 index 000000000000..69386d918823 --- /dev/null +++ b/src/com/owncloud/android/services/NCJobCreator.java @@ -0,0 +1,20 @@ +package com.owncloud.android.services; + +import com.evernote.android.job.Job; +import com.evernote.android.job.JobCreator; + +/** + * Created by mdjanic on 21/02/2017. + */ + +public class NCJobCreator implements JobCreator { + @Override + public Job create(String tag) { + switch (tag) { + case AutoUploadJob.TAG: + return new AutoUploadJob(); + default: + return null; + } + } +} diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index 6a9dd8d98904..ce4c9316aecf 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -181,7 +181,6 @@ public void destroy() throws Exception { while (fileAlterationListener.getActiveTasksCount() > 0) { SystemClock.sleep(250); } - } } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 1502a8614011..52787c7713fc 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -91,6 +91,7 @@ public void onDestroy() { FileAlterationMagicObserver fileAlterationMagicObserver = (FileAlterationMagicObserver) fileAlterationObserver; try { + fileAlterationMagicObserver.checkAndNotify(); fileAlterationMagicObserver.destroy(); } catch (Exception e) { Log_OC.d(TAG, "Something went very wrong on trying to destroy observers"); From c486b813e68b72ecfaae22d1b241b6bea875bd65 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 11:15:32 +0100 Subject: [PATCH 077/138] Fix a typo --- src/com/owncloud/android/services/AutoUploadJob.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/AutoUploadJob.java b/src/com/owncloud/android/services/AutoUploadJob.java index 86c3759f168a..1e4463c53227 100644 --- a/src/com/owncloud/android/services/AutoUploadJob.java +++ b/src/com/owncloud/android/services/AutoUploadJob.java @@ -38,7 +38,7 @@ public class AutoUploadJob extends Job { public static final String TAG = "AutoUploadJob"; - private static final String LOCAL_PATH = "filePath"; + public static final String LOCAL_PATH = "filePath"; public static final String REMOTE_PATH = "remotePath"; public static final String ACCOUNT = "account"; public static final String UPLOAD_BEHAVIOUR = "uploadBehaviour"; From 98319188bcd92683fd42372bb9e4a5f10ccf1bb4 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 11:36:00 +0100 Subject: [PATCH 078/138] Fix codacy stuff --- .../android/services/AutoUploadJob.java | 1 + .../services/FileAlterationMagicListener.java | 23 +++---------------- .../android/services/NCJobCreator.java | 22 +++++++++++++++++- .../android/services/ShutdownReceiver.java | 2 -- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/com/owncloud/android/services/AutoUploadJob.java b/src/com/owncloud/android/services/AutoUploadJob.java index 1e4463c53227..284d967bffaf 100644 --- a/src/com/owncloud/android/services/AutoUploadJob.java +++ b/src/com/owncloud/android/services/AutoUploadJob.java @@ -2,6 +2,7 @@ * Nextcloud Android client application * * @author Tobias Kaminsky + * Copyright (C) 2017 Mario Danic * Copyright (C) 2016 Tobias Kaminsky * Copyright (C) 2016 Nextcloud *

diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 7cf73ec57fc5..1c4d77637901 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -19,10 +19,8 @@ */ package com.owncloud.android.services; -import android.app.job.JobScheduler; import android.content.Context; import android.media.ExifInterface; -import android.os.Handler; import android.text.TextUtils; import com.evernote.android.job.JobRequest; @@ -56,9 +54,6 @@ public class FileAlterationMagicListener implements FileAlterationListener { private Context context; private SyncedFolder syncedFolder; - private Handler handler = new Handler(); - - //private Map fileRunnable = new HashMap<>(); private List filesList = new ArrayList<>(); @@ -128,9 +123,8 @@ public void onFileCreate(final File file) { bundle.putString(AutoUploadJob.ACCOUNT, syncedFolder.getAccount()); bundle.putInt(AutoUploadJob.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); - JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); - int jobId = new JobRequest.Builder(AutoUploadJob.TAG) + new JobRequest.Builder(AutoUploadJob.TAG) .setExecutionWindow(30_000L, 40_000L) .setRequiresCharging(syncedFolder.getChargingOnly()) .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobRequest.NetworkType.UNMETERED : @@ -140,31 +134,20 @@ public void onFileCreate(final File file) { .build() .schedule(); - //fileRunnable.remove(file.getAbsolutePath()); filesList.remove(file.getAbsolutePath()); - //fileRunnable.put(file.getAbsolutePath(), runnable); - //handler.post(runnable); } } @Override public void onFileChange(File file) { - /* Left here for later - if (fileRunnable.containsKey(file.getAbsolutePath())) { - handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); - handler.postDelayed(fileRunnable.get(file.getAbsolutePath()), 1500); - }*/ + // This method is intentionally empty } @Override public void onFileDelete(File file) { - /* Left here for later - if (fileRunnable.containsKey(file.getAbsolutePath())) { - handler.removeCallbacks(fileRunnable.get(file.getAbsolutePath())); - fileRunnable.remove(file.getAbsolutePath()); - }*/ + // This method is intentionally empty } @Override diff --git a/src/com/owncloud/android/services/NCJobCreator.java b/src/com/owncloud/android/services/NCJobCreator.java index 69386d918823..688adc5befa7 100644 --- a/src/com/owncloud/android/services/NCJobCreator.java +++ b/src/com/owncloud/android/services/NCJobCreator.java @@ -1,10 +1,30 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * Copyright (C) 2017 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ package com.owncloud.android.services; import com.evernote.android.job.Job; import com.evernote.android.job.JobCreator; /** - * Created by mdjanic on 21/02/2017. + * Job creator for android-job */ public class NCJobCreator implements JobCreator { diff --git a/src/com/owncloud/android/services/ShutdownReceiver.java b/src/com/owncloud/android/services/ShutdownReceiver.java index 4413510bdf63..940dd1e45ed5 100644 --- a/src/com/owncloud/android/services/ShutdownReceiver.java +++ b/src/com/owncloud/android/services/ShutdownReceiver.java @@ -31,8 +31,6 @@ */ public class ShutdownReceiver extends BroadcastReceiver { - private static final String TAG = "ShutdownReceiver"; - @Override public void onReceive(final Context context, final Intent intent) { if (MainApp.getSyncedFolderObserverService() != null) { From 38234af6814262f381ea05e04a4b02382830259d Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 17:10:16 +0100 Subject: [PATCH 079/138] Remove from monitor before destroying --- .../android/services/observer/SyncedFolderObserverService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 52787c7713fc..1d4e34b4c59e 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -91,6 +91,7 @@ public void onDestroy() { FileAlterationMagicObserver fileAlterationMagicObserver = (FileAlterationMagicObserver) fileAlterationObserver; try { + monitor.removeObserver(fileAlterationMagicObserver); fileAlterationMagicObserver.checkAndNotify(); fileAlterationMagicObserver.destroy(); } catch (Exception e) { From ab266f35c558dd57f6bb9c60446a19b2441bccef Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 20:12:01 +0100 Subject: [PATCH 080/138] Enforce requirements --- src/com/owncloud/android/services/AutoUploadJob.java | 1 + .../owncloud/android/services/FileAlterationMagicListener.java | 1 + .../android/services/observer/SyncedFolderObserverService.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/com/owncloud/android/services/AutoUploadJob.java b/src/com/owncloud/android/services/AutoUploadJob.java index 284d967bffaf..041bb1a205b5 100644 --- a/src/com/owncloud/android/services/AutoUploadJob.java +++ b/src/com/owncloud/android/services/AutoUploadJob.java @@ -75,6 +75,7 @@ protected Result onRunJob(Params params) { ); } + return Result.SUCCESS; } } diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 1c4d77637901..eec563b23171 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -131,6 +131,7 @@ public void onFileCreate(final File file) { JobRequest.NetworkType.ANY) .setExtras(bundle) .setPersisted(true) + .setRequirementsEnforced(true) .build() .schedule(); diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 1d4e34b4c59e..89ca4da1a773 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -86,6 +86,7 @@ public boolean accept(File pathname) { @Override public void onDestroy() { + super.onDestroy(); for(FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { FileAlterationMagicObserver fileAlterationMagicObserver = (FileAlterationMagicObserver) From d734e8a4f87ee933bad95b7570971f510e3a3907 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 20:19:55 +0100 Subject: [PATCH 081/138] Change execution window --- .../owncloud/android/services/FileAlterationMagicListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index eec563b23171..248f1dbd40ab 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -125,7 +125,7 @@ public void onFileCreate(final File file) { new JobRequest.Builder(AutoUploadJob.TAG) - .setExecutionWindow(30_000L, 40_000L) + .setExecutionWindow(30_000L, 80_000L) .setRequiresCharging(syncedFolder.getChargingOnly()) .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobRequest.NetworkType.UNMETERED : JobRequest.NetworkType.ANY) From 9ce087e94f155b97dadd0aaa7acd9770ff412552 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 23:00:55 +0100 Subject: [PATCH 082/138] Update support lib --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 429727b38c14..f456471b4653 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ apply plugin: 'pmd' apply plugin: 'findbugs' ext { - supportLibraryVersion = '24.2.1' + supportLibraryVersion = '25.0.0' travisBuild = System.getenv("TRAVIS") == "true" From 717e4b209648bb18fbd6c39d030bc738d922f0b7 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 23:14:56 +0100 Subject: [PATCH 083/138] Stuff --- AndroidManifest.xml | 1 + build.gradle | 1 + res/xml/backup_config.xml | 5 +++++ 3 files changed, 7 insertions(+) create mode 100644 res/xml/backup_config.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c3fa970d5707..0aeca76fef86 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -61,6 +61,7 @@ android:name=".MainApp" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" + android:fullBackupContent="@xml/backup_config" android:theme="@style/Theme.ownCloud.Toolbar" android:manageSpaceActivity="com.owncloud.android.ui.activity.ManageSpaceActivity"> + + + + From e4c306aa6b04a8b274ebb636cdbd2cf3b79dca71 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 23:37:51 +0100 Subject: [PATCH 084/138] Do not update current --- .../owncloud/android/services/FileAlterationMagicListener.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 248f1dbd40ab..4f0120fbf44c 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -132,6 +132,7 @@ public void onFileCreate(final File file) { .setExtras(bundle) .setPersisted(true) .setRequirementsEnforced(true) + .setUpdateCurrent(false) .build() .schedule(); From 115c9a7fd9de48ba8d73725a24b632bba5549560 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 23:49:18 +0100 Subject: [PATCH 085/138] Change order of things --- src/com/owncloud/android/MainApp.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index fc78e26eecb8..cd7e35211e80 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -86,6 +86,7 @@ public class MainApp extends Application { @SuppressFBWarnings("ST") public void onCreate() { super.onCreate(); + JobManager.create(this).addJobCreator(new NCJobCreator()); MainApp.mContext = getApplicationContext(); SharedPreferences appPrefs = @@ -118,8 +119,8 @@ public void onCreate() { cleanOldEntries(); - JobManager.create(this).addJobCreator(new NCJobCreator()); + JobManager.instance().setVerbose(true); Log_OC.d("SyncedFolderObserverService", "Start service SyncedFolderObserverService"); Intent i = new Intent(this, SyncedFolderObserverService.class); startService(i); From 9901a80b017f1ddd80c149380abe074033b6cea7 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 23:49:30 +0100 Subject: [PATCH 086/138] Remove verbose --- src/com/owncloud/android/MainApp.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index cd7e35211e80..8fca27c1c715 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -119,8 +119,6 @@ public void onCreate() { cleanOldEntries(); - - JobManager.instance().setVerbose(true); Log_OC.d("SyncedFolderObserverService", "Start service SyncedFolderObserverService"); Intent i = new Intent(this, SyncedFolderObserverService.class); startService(i); From 140f2d9b7bbad3a60910daf2faf83acd35fe2a32 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Tue, 21 Feb 2017 23:56:13 +0100 Subject: [PATCH 087/138] Remove obsolete stuff --- AndroidManifest.xml | 4 ---- build.gradle | 8 +++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0aeca76fef86..251a0daa2883 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -129,10 +129,6 @@ android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter_files" /> - Date: Wed, 22 Feb 2017 00:36:22 +0100 Subject: [PATCH 088/138] Do not persist --- .../services/FileAlterationMagicListener.java | 2 +- .../observer/SyncedFolderObserverService.java | 92 ++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 4f0120fbf44c..b851ab093152 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -130,7 +130,7 @@ public void onFileCreate(final File file) { .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobRequest.NetworkType.UNMETERED : JobRequest.NetworkType.ANY) .setExtras(bundle) - .setPersisted(true) + .setPersisted(false) .setRequirementsEnforced(true) .setUpdateCurrent(false) .build() diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 89ca4da1a773..e628d8c47d94 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -27,18 +27,28 @@ import android.os.Binder; import android.os.IBinder; +import com.evernote.android.job.JobManager; +import com.evernote.android.job.JobRequest; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.FileAlterationMagicListener; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; +import java.io.EOFException; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; @@ -46,12 +56,19 @@ public class SyncedFolderObserverService extends Service { private FileAlterationMonitor monitor; private FileFilter fileFilter; + private File file; + @Override public void onCreate() { SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext(). getContentResolver()); monitor = new FileAlterationMonitor(); + file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + File.separator + + "nc_persistence"); + + //schedulePersistedJobs(); + fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { @@ -84,11 +101,82 @@ public boolean accept(File pathname) { } + private void schedulePersistedJobs() { + if (!android.os.Build.MANUFACTURER.toLowerCase().contains("alcatel")) { + if (file.exists()) { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + ObjectInputStream ois = new ObjectInputStream(fis); + boolean cont = true; + while (cont) { + Object obj = ois.readObject(); + if (obj != null) { + JobRequest jobRequest = (JobRequest) obj; + JobManager.instance().schedule(jobRequest); + } else + cont = false; + } + + } catch (FileNotFoundException e) { + Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); + } catch (EOFException e) { + Log_OC.d(TAG, "Failed with EOFException while reading persistence file"); + } catch (IOException e) { + Log_OC.d(TAG, "Failed with IOException while reading persistence file"); + } catch (ClassNotFoundException e) { + Log_OC.d(TAG, "Failed with ClassNotFound while reading persistence file"); + } finally { + try { + if (fis != null) { + fis.close(); + } + } catch (IOException e) { + Log_OC.d(TAG, "Failed with closing FIS"); + } + } + } + FileUtils.deleteQuietly(file); + } + } + + private void syncToDisk() { + if (!android.os.Build.MANUFACTURER.toLowerCase().contains("alcatel")) { + + if (JobManager.instance().getAllJobRequests().size() > 0) { + try { + File newFile = new File(file.getAbsolutePath()); + + if (!newFile.exists()) { + newFile.createNewFile(); + } + + FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath()), false); + ObjectOutputStream os = new ObjectOutputStream(fos); + for (JobRequest jobRequest : JobManager.instance().getAllJobRequests()) { + os.writeObject(jobRequest); + } + + os.close(); + fos.close(); + + } catch (FileNotFoundException e) { + Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); + } catch (IOException e) { + Log_OC.d(TAG, "Failed writing to nc_persisten file via IOException"); + } + } else { + FileUtils.deleteQuietly(file); + } + } + + } + @Override public void onDestroy() { super.onDestroy(); - for(FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { + for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) { FileAlterationMagicObserver fileAlterationMagicObserver = (FileAlterationMagicObserver) fileAlterationObserver; try { @@ -99,6 +187,8 @@ public void onDestroy() { Log_OC.d(TAG, "Something went very wrong on trying to destroy observers"); } } + + //syncToDisk(); } @Override From 3860b94d078c52d3bf8fea6105864841cc02be49 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 00:40:03 +0100 Subject: [PATCH 089/138] Add multidex magic --- build.gradle | 2 ++ src/com/owncloud/android/MainApp.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2b701a4a7779..fb7632da3757 100644 --- a/build.gradle +++ b/build.gradle @@ -46,6 +46,7 @@ repositories { dependencies { /// dependencies for app building compile name: 'touch-image-view' + compile 'com.android.support:multidex:1.0.1' compile 'com.github.nextcloud:android-library:1.0.11' compile "com.android.support:support-v4:${supportLibraryVersion}" @@ -108,6 +109,7 @@ android { testInstrumentationRunnerArgument "TEST_PASSWORD", "\"$System.env.OCTEST_APP_PASSWORD\"" testInstrumentationRunnerArgument "TEST_SERVER_URL", "\"$System.env.OCTEST_SERVER_BASE_URL\"" + multiDexEnabled true applicationId "com.nextcloud.client" } diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index 8fca27c1c715..acb7c1dd1953 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -61,7 +61,7 @@ * Contains methods to build the "static" strings. These strings were before constants in different * classes */ -public class MainApp extends Application { +public class MainApp extends MultiDexApplication { private static final String TAG = MainApp.class.getSimpleName(); From 91257c83ab7fd5f82a5df029b80b22fa5f5180e4 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 00:40:25 +0100 Subject: [PATCH 090/138] Multidex import --- src/com/owncloud/android/MainApp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/owncloud/android/MainApp.java b/src/com/owncloud/android/MainApp.java index acb7c1dd1953..80ab58a98ff5 100644 --- a/src/com/owncloud/android/MainApp.java +++ b/src/com/owncloud/android/MainApp.java @@ -20,7 +20,6 @@ package com.owncloud.android; import android.app.Activity; -import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -32,6 +31,7 @@ import android.os.Environment; import android.os.IBinder; import android.preference.PreferenceManager; +import android.support.multidex.MultiDexApplication; import android.support.v4.util.Pair; import com.evernote.android.job.JobManager; From 4d6cc118b2223a9aa01e53dfe83f9eb4afc8080f Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 00:46:47 +0100 Subject: [PATCH 091/138] Update gradle --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index fb7632da3757..c3bb908f0b86 100644 --- a/build.gradle +++ b/build.gradle @@ -98,6 +98,11 @@ android { htmlReport true htmlOutput file("$project.buildDir/reports/lint/lint.html") } + + dexOptions { + javaMaxHeapSize "4g" + } + compileSdkVersion 24 buildToolsVersion "24.0.2" From f95446eaf132216c05e4471de9a3cc9c8861b900 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 01:00:54 +0100 Subject: [PATCH 092/138] Remove obsolete stuff --- .../observer/SyncedFolderObserverService.java | 92 +------------------ 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index e628d8c47d94..2b72a2dcde11 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -27,48 +27,31 @@ import android.os.Binder; import android.os.IBinder; -import com.evernote.android.job.JobManager; -import com.evernote.android.job.JobRequest; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.SyncedFolder; import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.FileAlterationMagicListener; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; -import java.io.EOFException; import java.io.File; import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; public class SyncedFolderObserverService extends Service { private static final String TAG = "SyncedFolderObserverService"; private final IBinder mBinder = new SyncedFolderObserverBinder(); private FileAlterationMonitor monitor; private FileFilter fileFilter; - - private File file; - + @Override public void onCreate() { SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext(). getContentResolver()); monitor = new FileAlterationMonitor(); - file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + File.separator + - "nc_persistence"); - - //schedulePersistedJobs(); - fileFilter = new FileFilter() { @Override public boolean accept(File pathname) { @@ -101,77 +84,6 @@ public boolean accept(File pathname) { } - private void schedulePersistedJobs() { - if (!android.os.Build.MANUFACTURER.toLowerCase().contains("alcatel")) { - if (file.exists()) { - FileInputStream fis = null; - try { - fis = new FileInputStream(file); - ObjectInputStream ois = new ObjectInputStream(fis); - boolean cont = true; - while (cont) { - Object obj = ois.readObject(); - if (obj != null) { - JobRequest jobRequest = (JobRequest) obj; - JobManager.instance().schedule(jobRequest); - } else - cont = false; - } - - } catch (FileNotFoundException e) { - Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file"); - } catch (EOFException e) { - Log_OC.d(TAG, "Failed with EOFException while reading persistence file"); - } catch (IOException e) { - Log_OC.d(TAG, "Failed with IOException while reading persistence file"); - } catch (ClassNotFoundException e) { - Log_OC.d(TAG, "Failed with ClassNotFound while reading persistence file"); - } finally { - try { - if (fis != null) { - fis.close(); - } - } catch (IOException e) { - Log_OC.d(TAG, "Failed with closing FIS"); - } - } - } - FileUtils.deleteQuietly(file); - } - } - - private void syncToDisk() { - if (!android.os.Build.MANUFACTURER.toLowerCase().contains("alcatel")) { - - if (JobManager.instance().getAllJobRequests().size() > 0) { - try { - File newFile = new File(file.getAbsolutePath()); - - if (!newFile.exists()) { - newFile.createNewFile(); - } - - FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath()), false); - ObjectOutputStream os = new ObjectOutputStream(fos); - for (JobRequest jobRequest : JobManager.instance().getAllJobRequests()) { - os.writeObject(jobRequest); - } - - os.close(); - fos.close(); - - } catch (FileNotFoundException e) { - Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound"); - } catch (IOException e) { - Log_OC.d(TAG, "Failed writing to nc_persisten file via IOException"); - } - } else { - FileUtils.deleteQuietly(file); - } - } - - } - @Override public void onDestroy() { @@ -187,8 +99,6 @@ public void onDestroy() { Log_OC.d(TAG, "Something went very wrong on trying to destroy observers"); } } - - //syncToDisk(); } @Override From 5548d17bc4acb2815be987edcc2140ef50b6e96b Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Tue, 21 Feb 2017 22:42:39 -0600 Subject: [PATCH 093/138] test new image Signed-off-by: Morris Jobke --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index c262805f3528..b00a744da8e6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,6 +1,6 @@ pipeline: test: - image: nextcloudci/android:android-7 + image: nextcloudci/android:android-14 commands: - echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M - emulator -avd test -no-window & From 9960434c4b0ac95259ce09f45cb6c507f10cba9b Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 09:40:14 +0100 Subject: [PATCH 094/138] Try to fix videos --- .../services/FileAlterationMagicListener.java | 74 +++++++++++-------- .../observer/SyncedFolderObserverService.java | 2 +- 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index b851ab093152..351de5222ac4 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -21,6 +21,7 @@ import android.content.Context; import android.media.ExifInterface; +import android.os.Handler; import android.text.TextUtils; import com.evernote.android.job.JobRequest; @@ -37,10 +38,10 @@ import java.io.IOException; import java.text.ParsePosition; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; -import java.util.List; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; /** @@ -55,7 +56,8 @@ public class FileAlterationMagicListener implements FileAlterationListener { private SyncedFolder syncedFolder; - private List filesList = new ArrayList<>(); + private Map uploadMap = new HashMap<>(); + private Handler handler = new Handler(); public FileAlterationMagicListener(SyncedFolder syncedFolder) { super(); @@ -87,7 +89,7 @@ public void onDirectoryDelete(File directory) { @Override public void onFileCreate(final File file) { if (file != null) { - filesList.add(file.getAbsolutePath()); + uploadMap.put(file.getAbsolutePath(), null); String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath()); Long lastModificationTime = file.lastModified(); @@ -113,31 +115,38 @@ public void onFileCreate(final File file) { final Long finalLastModificationTime = lastModificationTime; - PersistableBundleCompat bundle = new PersistableBundleCompat(); - bundle.putString(AutoUploadJob.LOCAL_PATH, file.getAbsolutePath()); - bundle.putString(AutoUploadJob.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( - currentLocale, - syncedFolder.getRemotePath(), file.getName(), - finalLastModificationTime, - syncedFolder.getSubfolderByDate())); - bundle.putString(AutoUploadJob.ACCOUNT, syncedFolder.getAccount()); - bundle.putInt(AutoUploadJob.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); - - - new JobRequest.Builder(AutoUploadJob.TAG) - .setExecutionWindow(30_000L, 80_000L) - .setRequiresCharging(syncedFolder.getChargingOnly()) - .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobRequest.NetworkType.UNMETERED : - JobRequest.NetworkType.ANY) - .setExtras(bundle) - .setPersisted(false) - .setRequirementsEnforced(true) - .setUpdateCurrent(false) - .build() - .schedule(); - - filesList.remove(file.getAbsolutePath()); + Runnable runnable = new Runnable() { + @Override + public void run() { + PersistableBundleCompat bundle = new PersistableBundleCompat(); + bundle.putString(AutoUploadJob.LOCAL_PATH, file.getAbsolutePath()); + bundle.putString(AutoUploadJob.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath( + currentLocale, + syncedFolder.getRemotePath(), file.getName(), + finalLastModificationTime, + syncedFolder.getSubfolderByDate())); + bundle.putString(AutoUploadJob.ACCOUNT, syncedFolder.getAccount()); + bundle.putInt(AutoUploadJob.UPLOAD_BEHAVIOUR, syncedFolder.getUploadAction()); + + + new JobRequest.Builder(AutoUploadJob.TAG) + .setExecutionWindow(30_000L, 80_000L) + .setRequiresCharging(syncedFolder.getChargingOnly()) + .setRequiredNetworkType(syncedFolder.getWifiOnly() ? JobRequest.NetworkType.UNMETERED : + JobRequest.NetworkType.ANY) + .setExtras(bundle) + .setPersisted(false) + .setRequirementsEnforced(true) + .setUpdateCurrent(false) + .build() + .schedule(); + + uploadMap.remove(file.getAbsolutePath()); + } + }; + uploadMap.put(file.getAbsolutePath(), runnable); + handler.postDelayed(runnable, 2000); } } @@ -145,6 +154,13 @@ public void onFileCreate(final File file) { @Override public void onFileChange(File file) { // This method is intentionally empty + if (uploadMap.containsKey(file.getAbsolutePath())) { + if (uploadMap.get(file.getAbsolutePath()) != null) { + handler.removeCallbacks(uploadMap.get(file.getAbsolutePath())); + } + uploadMap.remove(file.getAbsolutePath()); + } + onFileCreate(file); } @Override @@ -158,6 +174,6 @@ public void onStop(FileAlterationObserver observer) { } public int getActiveTasksCount() { - return filesList.size(); + return uploadMap.size(); } } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 2b72a2dcde11..63ddb772adf9 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -50,7 +50,7 @@ public class SyncedFolderObserverService extends Service { public void onCreate() { SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext(). getContentResolver()); - monitor = new FileAlterationMonitor(); + monitor = new FileAlterationMonitor(1000); fileFilter = new FileFilter() { @Override From 9ff5f2b7690a63f95c434f6d7499c27ce51c35e7 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 10:22:44 +0100 Subject: [PATCH 095/138] Fix empty stuff --- .../datamodel/SyncedFolderDisplayItem.java | 8 +++ .../ui/activity/FolderSyncActivity.java | 25 +++++++- .../android/ui/adapter/FolderSyncAdapter.java | 57 +++++++++++-------- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java b/src/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java index 35aca82a8c97..5ee7e90bef4d 100644 --- a/src/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java +++ b/src/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java @@ -57,6 +57,14 @@ public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boo this.numberOfFiles = numberOfFiles; } + public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly, + Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled, + String folderName) { + super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled); + this.folderName = folderName; + } + + public List getFilePaths() { return filePaths; } diff --git a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java index d3a7b8ae8719..75c1f3bd61a8 100644 --- a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java +++ b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java @@ -49,6 +49,7 @@ import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment; import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -167,15 +168,22 @@ private List mergeFolderData(List syncedF Map syncedFoldersMap = createSyncedFoldersMap(syncedFolders); List result = new ArrayList<>(); + for (MediaFolder mediaFolder : mediaFolders) { if (syncedFoldersMap.containsKey(mediaFolder.absolutePath)) { SyncedFolder syncedFolder = syncedFoldersMap.get(mediaFolder.absolutePath); + syncedFoldersMap.remove(mediaFolder.absolutePath); result.add(createSyncedFolder(syncedFolder, mediaFolder)); } else { result.add(createSyncedFolderFromMediaFolder(mediaFolder)); } } + for (SyncedFolder syncedFolder : syncedFoldersMap.values()) { + SyncedFolderDisplayItem syncedFolderDisplayItem = createSyncedFolderWithoutMediaFolder(syncedFolder); + result.add(syncedFolderDisplayItem); + } + return result; } @@ -220,6 +228,22 @@ public int compare(SyncedFolderDisplayItem f1, SyncedFolderDisplayItem f2) { return syncFolderItemList; } + @NonNull + private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull SyncedFolder syncedFolder) { + File file = new File(syncedFolder.getLocalPath()); + return new SyncedFolderDisplayItem( + syncedFolder.getId(), + syncedFolder.getLocalPath(), + syncedFolder.getRemotePath(), + syncedFolder.getWifiOnly(), + syncedFolder.getChargingOnly(), + syncedFolder.getSubfolderByDate(), + syncedFolder.getAccount(), + syncedFolder.getUploadAction(), + syncedFolder.isEnabled(), + new File(syncedFolder.getLocalPath()).getName()); + } + /** * creates a SyncedFolderDisplayItem merging a {@link SyncedFolder} and a {@link MediaFolder} object instance. * @@ -283,7 +307,6 @@ private Map createSyncedFoldersMap(List sync } return result; } - /** * show/hide recycler view list or the empty message / progress info. * diff --git a/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java b/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java index 47b1dbfe95c2..8c21374390d2 100644 --- a/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java @@ -77,7 +77,11 @@ public int getSectionCount() { @Override public int getItemCount(int section) { - return mSyncFolderItems.get(section).getFilePaths().size(); + if (mSyncFolderItems.get(section).getFilePaths() != null) { + return mSyncFolderItems.get(section).getFilePaths().size(); + } else { + return 1; + } } @Override @@ -108,37 +112,44 @@ public void onClick(View v) { @Override public void onBindViewHolder(MainViewHolder holder, int section, int relativePosition, int absolutePosition) { - File file = new File(mSyncFolderItems.get(section).getFilePaths().get(relativePosition)); + if (mSyncFolderItems.get(section).getFilePaths() != null) { + File file = new File(mSyncFolderItems.get(section).getFilePaths().get(relativePosition)); - ThumbnailsCacheManager.MediaThumbnailGenerationTask task = - new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image); + ThumbnailsCacheManager.MediaThumbnailGenerationTask task = + new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image); - ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable = - new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable( - mContext.getResources(), - ThumbnailsCacheManager.mDefaultImg, - task - ); - holder.image.setImageDrawable(asyncDrawable); + ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable = + new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable( + mContext.getResources(), + ThumbnailsCacheManager.mDefaultImg, + task + ); + holder.image.setImageDrawable(asyncDrawable); - task.execute(file); + task.execute(file); - // set proper tag - holder.image.setTag(file.hashCode()); + // set proper tag + holder.image.setTag(file.hashCode()); - holder.itemView.setTag(relativePosition % mGridWidth); + holder.itemView.setTag(relativePosition % mGridWidth); + + if (mSyncFolderItems.get(section).getNumberOfFiles() > mGridTotal && relativePosition >= mGridTotal - 1) { + holder.counterValue.setText(Long.toString(mSyncFolderItems.get(section).getNumberOfFiles() - mGridTotal)); + holder.counterBar.setVisibility(View.VISIBLE); + holder.thumbnailDarkener.setVisibility(View.VISIBLE); + } else { + holder.counterBar.setVisibility(View.GONE); + holder.thumbnailDarkener.setVisibility(View.GONE); + } - if (mSyncFolderItems.get(section).getNumberOfFiles() > mGridTotal && relativePosition >= mGridTotal - 1) { - holder.counterValue.setText(Long.toString(mSyncFolderItems.get(section).getNumberOfFiles() - mGridTotal)); + //holder.itemView.setTag(String.format(Locale.getDefault(), "%d:%d:%d", section, relativePos, absolutePos)); + //holder.itemView.setOnClickListener(this); + } else { + holder.itemView.setTag(relativePosition % mGridWidth); + holder.counterValue.setText(Long.toString(0)); holder.counterBar.setVisibility(View.VISIBLE); holder.thumbnailDarkener.setVisibility(View.VISIBLE); - } else { - holder.counterBar.setVisibility(View.GONE); - holder.thumbnailDarkener.setVisibility(View.GONE); } - - //holder.itemView.setTag(String.format(Locale.getDefault(), "%d:%d:%d", section, relativePos, absolutePos)); - //holder.itemView.setOnClickListener(this); } @Override From 759d0df4a957c7a6b547278729576fc7c2f841cb Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 10:44:20 +0100 Subject: [PATCH 096/138] Fix it all --- .../services/FileAlterationMagicListener.java | 25 +++-- .../observer/FileAlterationMagicObserver.java | 93 ++++++++++++------- .../observer/SyncedFolderObserverService.java | 8 +- 3 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 351de5222ac4..a7f2df795536 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -88,6 +88,10 @@ public void onDirectoryDelete(File directory) { @Override public void onFileCreate(final File file) { + onFileCreate(file, 2000); + } + + public void onFileCreate(final File file, int delay) { if (file != null) { uploadMap.put(file.getAbsolutePath(), null); @@ -146,26 +150,35 @@ public void run() { }; uploadMap.put(file.getAbsolutePath(), runnable); - handler.postDelayed(runnable, 2000); + handler.postDelayed(runnable, delay); } - } @Override public void onFileChange(File file) { - // This method is intentionally empty + onFileChange(file, 2000); + } + + public void onFileChange(File file, int delay) { if (uploadMap.containsKey(file.getAbsolutePath())) { if (uploadMap.get(file.getAbsolutePath()) != null) { - handler.removeCallbacks(uploadMap.get(file.getAbsolutePath())); + Runnable runnable = uploadMap.get(file.getAbsolutePath()); + handler.removeCallbacks(runnable); + handler.postDelayed(runnable, delay); } - uploadMap.remove(file.getAbsolutePath()); } - onFileCreate(file); } @Override public void onFileDelete(File file) { // This method is intentionally empty + if (uploadMap.containsKey(file.getAbsolutePath())) { + if (uploadMap.get(file.getAbsolutePath()) != null) { + Runnable runnable = uploadMap.get(file.getAbsolutePath()); + handler.removeCallbacks(runnable); + uploadMap.remove(file.getAbsolutePath()); + } + } } @Override diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index ce4c9316aecf..de5b1be651c3 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -46,7 +46,6 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.comparator.NameFileComparator; -import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationObserver; import org.apache.commons.io.monitor.FileEntry; @@ -62,15 +61,14 @@ public class FileAlterationMagicObserver extends FileAlterationObserver implements Serializable { private static final long serialVersionUID = 1185122225658782848L; - private final List listeners = new CopyOnWriteArrayList<>(); + private final List listeners = new CopyOnWriteArrayList<>(); private FileEntry rootEntry; private FileFilter fileFilter; private Comparator comparator; private SyncedFolder syncedFolder; private static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; - - + public FileAlterationMagicObserver(SyncedFolder syncedFolder, FileFilter fileFilter) { super(syncedFolder.getLocalPath(), fileFilter); @@ -120,7 +118,7 @@ public void setRootEntry(FileEntry rootEntry) { * * @param listener The file system listener */ - public void addListener(final FileAlterationListener listener) { + public void addListener(final FileAlterationMagicListener listener) { if (listener != null) { listeners.add(listener); } @@ -131,7 +129,7 @@ public void addListener(final FileAlterationListener listener) { * * @param listener The file system listener */ - public void removeListener(final FileAlterationListener listener) { + public void removeListener(final FileAlterationMagicListener listener) { if (listener != null) { while (listeners.remove(listener)) { } @@ -143,7 +141,7 @@ public void removeListener(final FileAlterationListener listener) { * * @return The file system listeners */ - public Iterable getListeners() { + public Iterable getMagicListeners() { return listeners; } @@ -175,46 +173,77 @@ public void init() throws Exception { * @throws Exception if an error occurs */ public void destroy() throws Exception { - Iterator iterator = getListeners().iterator(); + Iterator iterator = getMagicListeners().iterator(); while (iterator.hasNext()) { - FileAlterationMagicListener fileAlterationListener = (FileAlterationMagicListener) iterator.next(); - while (fileAlterationListener.getActiveTasksCount() > 0) { + FileAlterationMagicListener FileAlterationMagicListener = (FileAlterationMagicListener) iterator.next(); + while (FileAlterationMagicListener.getActiveTasksCount() > 0) { SystemClock.sleep(250); } } } + public void checkAndNotifyNow() { + /* fire onStart() */ + for (final FileAlterationMagicListener listener : listeners) { + listener.onStart(this); + } + + /* fire directory/file events */ + final File rootFile = rootEntry.getFile(); + if (rootFile.exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), 0); + } else if (rootEntry.isExists()) { + try { + // try to init once more + init(); + if (rootEntry.getFile().exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()), 0); + } else { + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 0); + } + } catch (Exception e) { + Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 0); + } + } // else didn't exist and still doesn't + + /* fire onStop() */ + for (final FileAlterationMagicListener listener : listeners) { + listener.onStop(this); + } + } + /** * Check whether the file and its children have been created, modified or deleted. */ public void checkAndNotify() { /* fire onStart() */ - for (final FileAlterationListener listener : listeners) { + for (final FileAlterationMagicListener listener : listeners) { listener.onStart(this); } /* fire directory/file events */ final File rootFile = rootEntry.getFile(); if (rootFile.exists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile)); + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), 2000); } else if (rootEntry.isExists()) { try { // try to init once more init(); if (rootEntry.getFile().exists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile())); + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()), 2000); } else { - checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); } } catch (Exception e) { Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); - checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); } } // else didn't exist and still doesn't /* fire onStop() */ - for (final FileAlterationListener listener : listeners) { + for (final FileAlterationMagicListener listener : listeners) { listener.onStop(this); } } @@ -226,28 +255,28 @@ public void checkAndNotify() { * @param previous The original list of files * @param files The current list of files */ - private void checkAndNotify(final FileEntry parent, final FileEntry[] previous, final File[] files) { + private void checkAndNotify(final FileEntry parent, final FileEntry[] previous, final File[] files, int delay) { int c = 0; final FileEntry[] current = files.length > 0 ? new FileEntry[files.length] : EMPTY_ENTRIES; for (final FileEntry entry : previous) { while (c < files.length && comparator.compare(entry.getFile(), files[c]) > 0) { current[c] = createFileEntry(parent, files[c]); - doCreate(current[c]); + doCreate(current[c], delay); c++; } if (c < files.length && comparator.compare(entry.getFile(), files[c]) == 0) { - doMatch(entry, files[c]); - checkAndNotify(entry, entry.getChildren(), listFiles(files[c])); + doMatch(entry, files[c], delay); + checkAndNotify(entry, entry.getChildren(), listFiles(files[c]), delay); current[c] = entry; c++; } else { - checkAndNotify(entry, entry.getChildren(), FileUtils.EMPTY_FILE_ARRAY); - doDelete(entry); + checkAndNotify(entry, entry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, delay); + doDelete(entry, delay); } } for (; c < files.length; c++) { current[c] = createFileEntry(parent, files[c]); - doCreate(current[c]); + doCreate(current[c], delay); } parent.setChildren(current); } @@ -288,17 +317,17 @@ private FileEntry[] doListFiles(File file, FileEntry entry) { * * @param entry The file entry */ - private void doCreate(final FileEntry entry) { - for (final FileAlterationListener listener : listeners) { + private void doCreate(final FileEntry entry, int delay) { + for (final FileAlterationMagicListener listener : listeners) { if (entry.isDirectory()) { listener.onDirectoryCreate(entry.getFile()); } else { - listener.onFileCreate(entry.getFile()); + listener.onFileCreate(entry.getFile(), delay); } } final FileEntry[] children = entry.getChildren(); for (final FileEntry aChildren : children) { - doCreate(aChildren); + doCreate(aChildren, delay); } } @@ -308,13 +337,13 @@ private void doCreate(final FileEntry entry) { * @param entry The previous file system entry * @param file The current file */ - private void doMatch(final FileEntry entry, final File file) { + private void doMatch(final FileEntry entry, final File file, int delay) { if (entry.refresh(file)) { - for (final FileAlterationListener listener : listeners) { + for (final FileAlterationMagicListener listener : listeners) { if (entry.isDirectory()) { listener.onDirectoryChange(file); } else { - listener.onFileChange(file); + listener.onFileChange(file, delay); } } } @@ -325,8 +354,8 @@ private void doMatch(final FileEntry entry, final File file) { * * @param entry The file entry */ - private void doDelete(final FileEntry entry) { - for (final FileAlterationListener listener : listeners) { + private void doDelete(final FileEntry entry, int delay) { + for (final FileAlterationMagicListener listener : listeners) { if (entry.isDirectory()) { listener.onDirectoryDelete(entry.getFile()); } else { diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 63ddb772adf9..86fe43e70402 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -33,7 +33,6 @@ import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.FileAlterationMagicListener; -import org.apache.commons.io.monitor.FileAlterationListener; import org.apache.commons.io.monitor.FileAlterationMonitor; import org.apache.commons.io.monitor.FileAlterationObserver; @@ -93,7 +92,7 @@ public void onDestroy() { fileAlterationObserver; try { monitor.removeObserver(fileAlterationMagicObserver); - fileAlterationMagicObserver.checkAndNotify(); + fileAlterationMagicObserver.checkAndNotifyNow(); fileAlterationMagicObserver.destroy(); } catch (Exception e) { Log_OC.d(TAG, "Something went very wrong on trying to destroy observers"); @@ -121,8 +120,9 @@ public void restartObserver(SyncedFolder syncedFolder) { (FileAlterationMagicObserver) fileAlterationObserver; if (fileAlterationMagicObserver.getSyncedFolderID() == syncedFolder.getId()) { if (syncedFolder.isEnabled()) { - for (FileAlterationListener fileAlterationListener : fileAlterationMagicObserver.getListeners()) { - fileAlterationMagicObserver.removeListener(fileAlterationListener); + for (FileAlterationMagicListener fileAlterationMagicListener : + fileAlterationMagicObserver.getMagicListeners()) { + fileAlterationMagicObserver.removeListener(fileAlterationMagicListener); } fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); } else { From 602b3c1982fbeda15ed928f92ccaab8f637240ed Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 10:53:39 +0100 Subject: [PATCH 097/138] =?UTF-8?q?Remove=20stuff=20we=20don=E2=80=99t=20n?= =?UTF-8?q?eed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/owncloud/android/ui/activity/FolderSyncActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java index 75c1f3bd61a8..2ec18f1ff7ce 100644 --- a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java +++ b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java @@ -230,7 +230,6 @@ public int compare(SyncedFolderDisplayItem f1, SyncedFolderDisplayItem f2) { @NonNull private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull SyncedFolder syncedFolder) { - File file = new File(syncedFolder.getLocalPath()); return new SyncedFolderDisplayItem( syncedFolder.getId(), syncedFolder.getLocalPath(), From 8804a019d8abdc6c5020981eb87aef01ce54956e Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 14:19:31 +0100 Subject: [PATCH 098/138] Try to fix changes between upload behaviour --- .../operations/UploadFileOperation.java | 55 +++++++++++-------- .../observer/SyncedFolderObserverService.java | 19 +++++-- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index 33e6f42f437a..4721bbb560bf 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -76,6 +76,8 @@ public class UploadFileOperation extends SyncOperation { public static final int CREATED_AS_INSTANT_PICTURE = 1; public static final int CREATED_AS_INSTANT_VIDEO = 2; + private String expectedPath; + public static OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) { // MIME type @@ -346,7 +348,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { throw new OperationCancelledException(); } - String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); + expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); expectedFile = new File(expectedPath); /// copy the file locally before uploading @@ -391,28 +393,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { /// move local temporal file or original file to its corresponding // location in the ownCloud local folder if (result.isSuccess()) { - if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) { - String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); - if (mOriginalStoragePath.equals(temporalPath)) { - // delete local file is was pre-copied in temporary folder (see .ui.helpers.UriUploader) - temporalFile = new File(temporalPath); - temporalFile.delete(); - } - mFile.setStoragePath(""); - } else if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE) { - originalFile.delete(); - } else { - mFile.setStoragePath(expectedPath); - - if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY - move(temporalFile, expectedFile); - } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE - move(originalFile, expectedFile); - getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath()); - } - FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath()); - } } else if (result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED ) { result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); @@ -452,6 +433,36 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (result.isSuccess()) { saveUploadedFile(client); + if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) { + String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); + if (mOriginalStoragePath.equals(temporalPath)) { + // delete local file is was pre-copied in temporary folder (see .ui.helpers.UriUploader) + temporalFile = new File(temporalPath); + temporalFile.delete(); + } + mFile.setStoragePath(""); + + } else if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE) { + originalFile.delete(); + } else { + mFile.setStoragePath(expectedPath); + + if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY + try { + move(temporalFile, expectedFile); + } catch (IOException e) { + e.printStackTrace(); + } + } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE + try { + move(originalFile, expectedFile); + } catch (IOException e) { + e.printStackTrace(); + } + getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath()); + } + FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath()); + } } else if (result.getCode() == ResultCode.SYNC_CONFLICT) { getStorageManager().saveConflict(mFile, mFile.getEtagInConflict()); } diff --git a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java index 86fe43e70402..b1671bfa613f 100644 --- a/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java +++ b/src/com/owncloud/android/services/observer/SyncedFolderObserverService.java @@ -119,12 +119,23 @@ public void restartObserver(SyncedFolder syncedFolder) { fileAlterationMagicObserver = (FileAlterationMagicObserver) fileAlterationObserver; if (fileAlterationMagicObserver.getSyncedFolderID() == syncedFolder.getId()) { + monitor.removeObserver(fileAlterationObserver); + fileAlterationMagicObserver.checkAndNotifyNow(); + try { + fileAlterationMagicObserver.destroy(); + } catch (Exception e) { + Log_OC.d(TAG, "Failed to destroy the observer in restart"); + } + if (syncedFolder.isEnabled()) { - for (FileAlterationMagicListener fileAlterationMagicListener : - fileAlterationMagicObserver.getMagicListeners()) { - fileAlterationMagicObserver.removeListener(fileAlterationMagicListener); + try { + fileAlterationMagicObserver = new FileAlterationMagicObserver(syncedFolder, fileFilter); + fileAlterationMagicObserver.init(); + fileAlterationMagicObserver.addListener(new FileAlterationMagicListener(syncedFolder)); + monitor.addObserver(fileAlterationMagicObserver); + } catch (Exception e) { + Log_OC.d(TAG, "Failed getting an observer to intialize"); } - fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder)); } else { monitor.removeObserver(fileAlterationObserver); } From 004cfd5760b1c1ee25438d66baf7a7816a619283 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Wed, 22 Feb 2017 15:20:32 +0100 Subject: [PATCH 099/138] Revert "Try to fix changes between upload behaviour" This reverts commit c61ad342e462ebba43a4022d4214ed2bfe13cb6f. --- .../operations/UploadFileOperation.java | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/com/owncloud/android/operations/UploadFileOperation.java b/src/com/owncloud/android/operations/UploadFileOperation.java index 4721bbb560bf..33e6f42f437a 100644 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@ -76,8 +76,6 @@ public class UploadFileOperation extends SyncOperation { public static final int CREATED_AS_INSTANT_PICTURE = 1; public static final int CREATED_AS_INSTANT_VIDEO = 2; - private String expectedPath; - public static OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) { // MIME type @@ -348,7 +346,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { throw new OperationCancelledException(); } - expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); + String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); expectedFile = new File(expectedPath); /// copy the file locally before uploading @@ -393,7 +391,28 @@ protected RemoteOperationResult run(OwnCloudClient client) { /// move local temporal file or original file to its corresponding // location in the ownCloud local folder if (result.isSuccess()) { + if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) { + String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); + if (mOriginalStoragePath.equals(temporalPath)) { + // delete local file is was pre-copied in temporary folder (see .ui.helpers.UriUploader) + temporalFile = new File(temporalPath); + temporalFile.delete(); + } + mFile.setStoragePath(""); + } else if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE) { + originalFile.delete(); + } else { + mFile.setStoragePath(expectedPath); + + if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY + move(temporalFile, expectedFile); + } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE + move(originalFile, expectedFile); + getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath()); + } + FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath()); + } } else if (result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED ) { result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); @@ -433,36 +452,6 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (result.isSuccess()) { saveUploadedFile(client); - if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) { - String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); - if (mOriginalStoragePath.equals(temporalPath)) { - // delete local file is was pre-copied in temporary folder (see .ui.helpers.UriUploader) - temporalFile = new File(temporalPath); - temporalFile.delete(); - } - mFile.setStoragePath(""); - - } else if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_DELETE) { - originalFile.delete(); - } else { - mFile.setStoragePath(expectedPath); - - if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY - try { - move(temporalFile, expectedFile); - } catch (IOException e) { - e.printStackTrace(); - } - } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE - try { - move(originalFile, expectedFile); - } catch (IOException e) { - e.printStackTrace(); - } - getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath()); - } - FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath()); - } } else if (result.getCode() == ResultCode.SYNC_CONFLICT) { getStorageManager().saveConflict(mFile, mFile.getEtagInConflict()); } From 8bfdd0047ca55e0e0e986e428b9a35e763ce5f74 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 23 Feb 2017 10:23:54 +0100 Subject: [PATCH 100/138] Attempt to fix stuff --- .../services/FileAlterationMagicListener.java | 2 +- .../observer/FileAlterationMagicObserver.java | 46 +++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index a7f2df795536..3d662fab0301 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -92,7 +92,7 @@ public void onFileCreate(final File file) { } public void onFileCreate(final File file, int delay) { - if (file != null) { + if (file != null && !uploadMap.containsKey(file.getAbsolutePath())) { uploadMap.put(file.getAbsolutePath(), null); String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath()); diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index de5b1be651c3..dd640eab28cd 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -66,6 +66,7 @@ public class FileAlterationMagicObserver extends FileAlterationObserver implemen private FileFilter fileFilter; private Comparator comparator; private SyncedFolder syncedFolder; + private boolean isCheckRunning = false; private static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; @@ -218,33 +219,38 @@ public void checkAndNotifyNow() { */ public void checkAndNotify() { + if (!isCheckRunning) { + isCheckRunning = true; /* fire onStart() */ - for (final FileAlterationMagicListener listener : listeners) { - listener.onStart(this); - } + for (final FileAlterationMagicListener listener : listeners) { + listener.onStart(this); + } /* fire directory/file events */ - final File rootFile = rootEntry.getFile(); - if (rootFile.exists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), 2000); - } else if (rootEntry.isExists()) { - try { - // try to init once more - init(); - if (rootEntry.getFile().exists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()), 2000); - } else { + final File rootFile = rootEntry.getFile(); + if (rootFile.exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), 2000); + } else if (rootEntry.isExists()) { + try { + // try to init once more + init(); + if (rootEntry.getFile().exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()), 2000); + } else { + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); + } + } catch (Exception e) { + Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); } - } catch (Exception e) { - Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); - checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); - } - } // else didn't exist and still doesn't + } // else didn't exist and still doesn't /* fire onStop() */ - for (final FileAlterationMagicListener listener : listeners) { - listener.onStop(this); + for (final FileAlterationMagicListener listener : listeners) { + listener.onStop(this); + } + + isCheckRunning = false; } } From 49c27b146490fa5e392eb08576e63fb1ae927f12 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 23 Feb 2017 10:39:35 +0100 Subject: [PATCH 101/138] Revert "Attempt to fix stuff" This reverts commit 58b640a8c85f090c9d8b9fc8de342e95a708f7a0. --- .../services/FileAlterationMagicListener.java | 2 +- .../observer/FileAlterationMagicObserver.java | 46 ++++++++----------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/com/owncloud/android/services/FileAlterationMagicListener.java b/src/com/owncloud/android/services/FileAlterationMagicListener.java index 3d662fab0301..a7f2df795536 100644 --- a/src/com/owncloud/android/services/FileAlterationMagicListener.java +++ b/src/com/owncloud/android/services/FileAlterationMagicListener.java @@ -92,7 +92,7 @@ public void onFileCreate(final File file) { } public void onFileCreate(final File file, int delay) { - if (file != null && !uploadMap.containsKey(file.getAbsolutePath())) { + if (file != null) { uploadMap.put(file.getAbsolutePath(), null); String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath()); diff --git a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java index dd640eab28cd..de5b1be651c3 100644 --- a/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java +++ b/src/com/owncloud/android/services/observer/FileAlterationMagicObserver.java @@ -66,7 +66,6 @@ public class FileAlterationMagicObserver extends FileAlterationObserver implemen private FileFilter fileFilter; private Comparator comparator; private SyncedFolder syncedFolder; - private boolean isCheckRunning = false; private static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0]; @@ -219,38 +218,33 @@ public void checkAndNotifyNow() { */ public void checkAndNotify() { - if (!isCheckRunning) { - isCheckRunning = true; /* fire onStart() */ - for (final FileAlterationMagicListener listener : listeners) { - listener.onStart(this); - } + for (final FileAlterationMagicListener listener : listeners) { + listener.onStart(this); + } /* fire directory/file events */ - final File rootFile = rootEntry.getFile(); - if (rootFile.exists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), 2000); - } else if (rootEntry.isExists()) { - try { - // try to init once more - init(); - if (rootEntry.getFile().exists()) { - checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()), 2000); - } else { - checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); - } - } catch (Exception e) { - Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); + final File rootFile = rootEntry.getFile(); + if (rootFile.exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), 2000); + } else if (rootEntry.isExists()) { + try { + // try to init once more + init(); + if (rootEntry.getFile().exists()) { + checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()), 2000); + } else { checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); } - } // else didn't exist and still doesn't - - /* fire onStop() */ - for (final FileAlterationMagicListener listener : listeners) { - listener.onStop(this); + } catch (Exception e) { + Log_OC.d("FileAlterationMagicObserver", "Failed getting an observer to intialize " + e); + checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, 2000); } + } // else didn't exist and still doesn't - isCheckRunning = false; + /* fire onStop() */ + for (final FileAlterationMagicListener listener : listeners) { + listener.onStop(this); } } From c935617898419936c607238abf916da4a3b9c790 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 23 Feb 2017 10:49:24 +0100 Subject: [PATCH 102/138] Attempt to fix --- AndroidManifest.xml | 2 +- .../observer/FileAlterationMagicObserver.java | 40 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 251a0daa2883..b13fa200a097 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -25,7 +25,7 @@ + android:targetSdkVersion="25" />