mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 13:45:35 +03:00
Clean up code
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
5701d3bd13
commit
0bae6fcfb2
6 changed files with 2 additions and 877 deletions
|
@ -131,7 +131,7 @@
|
|||
android:name="android.accounts.AccountAuthenticator"
|
||||
android:resource="@xml/authenticator" />
|
||||
</service>
|
||||
<service android:name=".services.observer.SyncedFolderObserverService"/>
|
||||
|
||||
<service
|
||||
android:name=".syncadapter.FileSyncService"
|
||||
android:exported="true" >
|
||||
|
|
|
@ -20,16 +20,12 @@
|
|||
package com.owncloud.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.support.multidex.MultiDexApplication;
|
||||
import android.support.v4.util.Pair;
|
||||
|
||||
|
@ -39,11 +35,10 @@ import com.owncloud.android.datamodel.SyncedFolder;
|
|||
import com.owncloud.android.datamodel.SyncedFolderProvider;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.db.PreferenceManager;
|
||||
import com.owncloud.android.jobs.NCJobCreator;
|
||||
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.jobs.NCJobCreator;
|
||||
import com.owncloud.android.services.observer.SyncedFolderObserverService;
|
||||
import com.owncloud.android.ui.activity.Preferences;
|
||||
import com.owncloud.android.ui.activity.WhatsNewActivity;
|
||||
import com.owncloud.android.utils.AnalyticsUtils;
|
||||
|
@ -79,8 +74,6 @@ public class MainApp extends MultiDexApplication {
|
|||
|
||||
private static boolean mOnlyOnDevice = false;
|
||||
|
||||
private static SyncedFolderObserverService mObserverService;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private boolean mBound;
|
||||
|
||||
|
@ -121,12 +114,6 @@ public class MainApp extends MultiDexApplication {
|
|||
cleanOldEntries();
|
||||
updateAutoUploadEntries();
|
||||
|
||||
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() {
|
||||
|
||||
|
@ -245,10 +232,6 @@ public class MainApp extends MultiDexApplication {
|
|||
return mOnlyOnDevice;
|
||||
}
|
||||
|
||||
public static SyncedFolderObserverService getSyncedFolderObserverService() {
|
||||
return mObserverService;
|
||||
}
|
||||
|
||||
// user agent
|
||||
public static String getUserAgent() {
|
||||
String appString = getAppContext().getResources().getString(R.string.user_agent);
|
||||
|
@ -313,24 +296,4 @@ public class MainApp extends MultiDexApplication {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines callbacks for service binding, passed to bindService()
|
||||
*/
|
||||
private ServiceConnection syncedFolderObserverServiceConnection = new ServiceConnection() {
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
SyncedFolderObserverService.SyncedFolderObserverBinder binder =
|
||||
(SyncedFolderObserverService.SyncedFolderObserverBinder) service;
|
||||
mObserverService = binder.getService();
|
||||
mBound = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0) {
|
||||
mBound = false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import android.database.Cursor;
|
|||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.db.PreferenceManager;
|
||||
import com.owncloud.android.db.ProviderMeta;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
@ -71,7 +70,6 @@ public class SyncedFolderProvider extends Observable {
|
|||
Uri result = mContentResolver.insert(ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS, cv);
|
||||
|
||||
if (result != null) {
|
||||
notifyFolderSyncObservers(syncedFolder);
|
||||
return Long.parseLong(result.getPathSegments().get(1));
|
||||
} else {
|
||||
Log_OC.e(TAG, "Failed to insert item " + syncedFolder.getLocalPath() + " into folder sync db.");
|
||||
|
@ -299,10 +297,6 @@ public class SyncedFolderProvider extends Observable {
|
|||
new String[]{String.valueOf(syncedFolder.getId())}
|
||||
);
|
||||
|
||||
if (result > 0) {
|
||||
notifyFolderSyncObservers(syncedFolder);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -362,16 +356,4 @@ public class SyncedFolderProvider extends Observable {
|
|||
|
||||
return cv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform all observers about data change.
|
||||
*
|
||||
* @param syncedFolder changed, synchronized folder
|
||||
*/
|
||||
private void notifyFolderSyncObservers(SyncedFolder syncedFolder) {
|
||||
if (syncedFolder != null) {
|
||||
MainApp.getSyncedFolderObserverService().restartObserver(syncedFolder);
|
||||
Log_OC.d(TAG, "notifying folder sync data observers for changed/added: " + syncedFolder.getLocalPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,238 +0,0 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.services;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.media.ExifInterface;
|
||||
import android.os.Handler;
|
||||
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.R;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.SyncedFolder;
|
||||
import com.owncloud.android.jobs.AutoUploadJob;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.ui.activity.Preferences;
|
||||
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.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
|
||||
*/
|
||||
|
||||
public class AdvancedFileAlterationListener implements FileAlterationListener {
|
||||
|
||||
public static final String TAG = "AdvancedFileAlterationListener";
|
||||
public static final int DELAY_INVOCATION_MS = 2500;
|
||||
private Context context;
|
||||
private boolean lightVersion;
|
||||
|
||||
private SyncedFolder syncedFolder;
|
||||
|
||||
private Map<String, Runnable> uploadMap = new HashMap<>();
|
||||
private Handler handler = new Handler();
|
||||
|
||||
public AdvancedFileAlterationListener(SyncedFolder syncedFolder, boolean lightVersion) {
|
||||
super();
|
||||
|
||||
context = MainApp.getAppContext();
|
||||
this.lightVersion = lightVersion;
|
||||
this.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
|
||||
public void onFileCreate(final File file) {
|
||||
onFileCreate(file, DELAY_INVOCATION_MS);
|
||||
}
|
||||
|
||||
public void onFileCreate(final File file, int delay) {
|
||||
if (file != null) {
|
||||
uploadMap.put(file.getAbsolutePath(), null);
|
||||
|
||||
String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath());
|
||||
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());
|
||||
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", currentLocale);
|
||||
sFormatter.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()));
|
||||
Date dateTime = sFormatter.parse(exifDate, pos);
|
||||
lastModificationTime = dateTime.getTime();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
Log_OC.d(TAG, "Failed to get the proper time " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final Long finalLastModificationTime = lastModificationTime;
|
||||
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
String remotePath;
|
||||
boolean subfolderByDate;
|
||||
boolean chargingOnly;
|
||||
boolean wifiOnly;
|
||||
Integer uploadAction;
|
||||
String accountName = syncedFolder.getAccount();
|
||||
|
||||
if (lightVersion) {
|
||||
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context
|
||||
.getContentResolver());
|
||||
|
||||
Resources resources = MainApp.getAppContext().getResources();
|
||||
|
||||
remotePath = resources.getString(R.string.syncedFolder_remote_folder) + OCFile.PATH_SEPARATOR +
|
||||
new File(syncedFolder.getLocalPath()).getName() + OCFile.PATH_SEPARATOR;
|
||||
subfolderByDate = resources.getBoolean(R.bool.syncedFolder_light_use_subfolders);
|
||||
chargingOnly = resources.getBoolean(R.bool.syncedFolder_light_on_charging);
|
||||
wifiOnly = arbitraryDataProvider.getBooleanValue(accountName,
|
||||
Preferences.SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI);
|
||||
String uploadActionString = resources.getString(R.string.syncedFolder_light_upload_behaviour);
|
||||
uploadAction = getUploadAction(uploadActionString);
|
||||
} else {
|
||||
remotePath = syncedFolder.getRemotePath();
|
||||
subfolderByDate = syncedFolder.getSubfolderByDate();
|
||||
chargingOnly = syncedFolder.getChargingOnly();
|
||||
wifiOnly = syncedFolder.getWifiOnly();
|
||||
uploadAction = syncedFolder.getUploadAction();
|
||||
}
|
||||
|
||||
PersistableBundleCompat bundle = new PersistableBundleCompat();
|
||||
bundle.putString(AutoUploadJob.LOCAL_PATH, file.getAbsolutePath());
|
||||
bundle.putString(AutoUploadJob.REMOTE_PATH, FileStorageUtils.getInstantUploadFilePath(
|
||||
currentLocale,
|
||||
remotePath, file.getName(),
|
||||
finalLastModificationTime,
|
||||
subfolderByDate));
|
||||
bundle.putString(AutoUploadJob.ACCOUNT, accountName);
|
||||
bundle.putInt(AutoUploadJob.UPLOAD_BEHAVIOUR, uploadAction);
|
||||
|
||||
new JobRequest.Builder(AutoUploadJob.TAG)
|
||||
.setExecutionWindow(30_000L, 80_000L)
|
||||
.setRequiresCharging(chargingOnly)
|
||||
.setRequiredNetworkType(wifiOnly ? 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, delay);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getUploadAction(String action) {
|
||||
switch (action) {
|
||||
case "LOCAL_BEHAVIOUR_FORGET":
|
||||
return FileUploader.LOCAL_BEHAVIOUR_FORGET;
|
||||
case "LOCAL_BEHAVIOUR_MOVE":
|
||||
return FileUploader.LOCAL_BEHAVIOUR_MOVE;
|
||||
case "LOCAL_BEHAVIOUR_DELETE":
|
||||
return FileUploader.LOCAL_BEHAVIOUR_DELETE;
|
||||
default:
|
||||
return FileUploader.LOCAL_BEHAVIOUR_FORGET;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileChange(File file) {
|
||||
onFileChange(file, 2500);
|
||||
}
|
||||
|
||||
public void onFileChange(File file, int delay) {
|
||||
Runnable runnable;
|
||||
if ((runnable = uploadMap.get(file.getAbsolutePath())) != null) {
|
||||
handler.removeCallbacks(runnable);
|
||||
handler.postDelayed(runnable, delay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDelete(File file) {
|
||||
Runnable runnable;
|
||||
if ((runnable = uploadMap.get(file.getAbsolutePath())) != null) {
|
||||
handler.removeCallbacks(runnable);
|
||||
uploadMap.remove(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop(FileAlterationObserver observer) {
|
||||
// This method is intentionally empty
|
||||
}
|
||||
|
||||
public int getActiveTasksCount() {
|
||||
return uploadMap.size();
|
||||
}
|
||||
}
|
|
@ -1,402 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* All changes are under the same licence as the original.
|
||||
*
|
||||
*/
|
||||
package com.owncloud.android.services.observer;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.owncloud.android.datamodel.SyncedFolder;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.services.AdvancedFileAlterationListener;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.comparator.NameFileComparator;
|
||||
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.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class AdvancedFileAlterationObserver extends FileAlterationObserver implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1185122225658782848L;
|
||||
private static final int DELAY_INVOCATION_MS = 2500;
|
||||
private final List<AdvancedFileAlterationListener> listeners = new CopyOnWriteArrayList<>();
|
||||
private FileEntry rootEntry;
|
||||
private FileFilter fileFilter;
|
||||
private Comparator<File> comparator;
|
||||
private SyncedFolder syncedFolder;
|
||||
|
||||
private static final FileEntry[] EMPTY_ENTRIES = new FileEntry[0];
|
||||
|
||||
public AdvancedFileAlterationObserver(SyncedFolder syncedFolder, FileFilter fileFilter) {
|
||||
super(syncedFolder.getLocalPath(), fileFilter);
|
||||
|
||||
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.
|
||||
*
|
||||
* @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 AdvancedFileAlterationListener listener) {
|
||||
if (listener != null) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file system listener.
|
||||
*
|
||||
* @param listener The file system listener
|
||||
*/
|
||||
public void removeListener(final AdvancedFileAlterationListener listener) {
|
||||
if (listener != null) {
|
||||
while (listeners.remove(listener)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of registered file system listeners.
|
||||
*
|
||||
* @return The file system listeners
|
||||
*/
|
||||
public Iterable<AdvancedFileAlterationListener> getMagicListeners() {
|
||||
return listeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing - hack for the monitor
|
||||
*
|
||||
*
|
||||
*/
|
||||
public void initialize() {
|
||||
// does nothing - hack the monitor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
Iterator iterator = getMagicListeners().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AdvancedFileAlterationListener AdvancedFileAlterationListener = (AdvancedFileAlterationListener) iterator.next();
|
||||
while (AdvancedFileAlterationListener.getActiveTasksCount() > 0) {
|
||||
SystemClock.sleep(250);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkAndNotifyNow() {
|
||||
/* fire onStart() */
|
||||
for (final AdvancedFileAlterationListener 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("AdvancedFileAlterationObserver", "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 AdvancedFileAlterationListener 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 AdvancedFileAlterationListener listener : listeners) {
|
||||
listener.onStart(this);
|
||||
}
|
||||
|
||||
/* fire directory/file events */
|
||||
final File rootFile = rootEntry.getFile();
|
||||
if (rootFile.exists()) {
|
||||
checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootFile), DELAY_INVOCATION_MS);
|
||||
} else if (rootEntry.isExists()) {
|
||||
try {
|
||||
// try to init once more
|
||||
init();
|
||||
if (rootEntry.getFile().exists()) {
|
||||
checkAndNotify(rootEntry, rootEntry.getChildren(), listFiles(rootEntry.getFile()),
|
||||
DELAY_INVOCATION_MS);
|
||||
} else {
|
||||
checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, DELAY_INVOCATION_MS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log_OC.d("AdvancedFileAlterationObserver", "Failed getting an observer to intialize " + e);
|
||||
checkAndNotify(rootEntry, rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY, DELAY_INVOCATION_MS);
|
||||
}
|
||||
} // else didn't exist and still doesn't
|
||||
|
||||
/* fire onStop() */
|
||||
for (final AdvancedFileAlterationListener 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 delay) {
|
||||
if (files != null && files.length > 0) {
|
||||
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], delay);
|
||||
c++;
|
||||
}
|
||||
if (c < files.length && comparator.compare(entry.getFile(), files[c]) == 0) {
|
||||
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, delay);
|
||||
doDelete(entry);
|
||||
}
|
||||
}
|
||||
for (; c < files.length; c++) {
|
||||
current[c] = createFileEntry(parent, files[c]);
|
||||
doCreate(current[c], delay);
|
||||
}
|
||||
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, int delay) {
|
||||
for (final AdvancedFileAlterationListener listener : listeners) {
|
||||
if (entry.isDirectory()) {
|
||||
listener.onDirectoryCreate(entry.getFile());
|
||||
} else {
|
||||
listener.onFileCreate(entry.getFile(), delay);
|
||||
}
|
||||
}
|
||||
final FileEntry[] children = entry.getChildren();
|
||||
for (final FileEntry aChildren : children) {
|
||||
doCreate(aChildren, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, int delay) {
|
||||
if (entry.refresh(file)) {
|
||||
for (final AdvancedFileAlterationListener listener : listeners) {
|
||||
if (entry.isDirectory()) {
|
||||
listener.onDirectoryChange(file);
|
||||
} else {
|
||||
listener.onFileChange(file, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire directory/file delete events to the registered listeners.
|
||||
*
|
||||
* @param entry The file entry
|
||||
*/
|
||||
private void doDelete(final FileEntry entry) {
|
||||
for (final AdvancedFileAlterationListener 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* @author Andy Scherzinger
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2016 Tobias Kaminsky, Andy Scherzinger
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.services.observer;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
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.AdvancedFileAlterationListener;
|
||||
|
||||
import org.apache.commons.io.monitor.FileAlterationMonitor;
|
||||
import org.apache.commons.io.monitor.FileAlterationObserver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
public class SyncedFolderObserverService extends Service {
|
||||
private static final String TAG = "SyncedFolderObserverService";
|
||||
|
||||
private static final int MONITOR_SCAN_INTERVAL = 1000;
|
||||
|
||||
private final IBinder mBinder = new SyncedFolderObserverBinder();
|
||||
private FileAlterationMonitor monitor;
|
||||
private FileFilter fileFilter;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().
|
||||
getContentResolver());
|
||||
monitor = new FileAlterationMonitor(MONITOR_SCAN_INTERVAL);
|
||||
|
||||
fileFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
return !pathname.getName().startsWith(".") && !pathname.getName().endsWith(".tmp") &&
|
||||
!pathname.getName().endsWith(".temp") && !pathname.getName().endsWith(".thumbnail");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
|
||||
if (syncedFolder.isEnabled()) {
|
||||
AdvancedFileAlterationObserver observer = new AdvancedFileAlterationObserver(syncedFolder, fileFilter);
|
||||
|
||||
try {
|
||||
observer.init();
|
||||
observer.addListener(new AdvancedFileAlterationListener(syncedFolder,
|
||||
getResources().getBoolean(R.bool.syncedFolder_light)));
|
||||
monitor.addObserver(observer);
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Failed getting an observer to initialize " + e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
monitor.start();
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Something went very wrong at onStartCommand");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
super.onDestroy();
|
||||
for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) {
|
||||
AdvancedFileAlterationObserver advancedFileAlterationObserver = (AdvancedFileAlterationObserver)
|
||||
fileAlterationObserver;
|
||||
try {
|
||||
monitor.removeObserver(advancedFileAlterationObserver);
|
||||
advancedFileAlterationObserver.checkAndNotifyNow();
|
||||
advancedFileAlterationObserver.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart oberver if it is enabled
|
||||
* If syncedFolder exists already, use it, otherwise create new observer
|
||||
*
|
||||
* @param syncedFolder
|
||||
*/
|
||||
|
||||
public void restartObserver(SyncedFolder syncedFolder) {
|
||||
boolean found = false;
|
||||
AdvancedFileAlterationObserver advancedFileAlterationObserver;
|
||||
for (FileAlterationObserver fileAlterationObserver : monitor.getObservers()) {
|
||||
advancedFileAlterationObserver =
|
||||
(AdvancedFileAlterationObserver) fileAlterationObserver;
|
||||
if (advancedFileAlterationObserver.getSyncedFolderID() == syncedFolder.getId()) {
|
||||
monitor.removeObserver(fileAlterationObserver);
|
||||
advancedFileAlterationObserver.checkAndNotifyNow();
|
||||
try {
|
||||
advancedFileAlterationObserver.destroy();
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Failed to destroy the observer in restart");
|
||||
}
|
||||
|
||||
if (syncedFolder.isEnabled()) {
|
||||
try {
|
||||
advancedFileAlterationObserver = new AdvancedFileAlterationObserver(syncedFolder, fileFilter);
|
||||
advancedFileAlterationObserver.init();
|
||||
advancedFileAlterationObserver.addListener(new AdvancedFileAlterationListener(syncedFolder,
|
||||
getResources().getBoolean(R.bool.syncedFolder_light)));
|
||||
monitor.addObserver(advancedFileAlterationObserver);
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Failed getting an observer to initialize");
|
||||
}
|
||||
} else {
|
||||
monitor.removeObserver(fileAlterationObserver);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && syncedFolder.isEnabled()) {
|
||||
try {
|
||||
advancedFileAlterationObserver = new AdvancedFileAlterationObserver(syncedFolder, fileFilter);
|
||||
advancedFileAlterationObserver.init();
|
||||
advancedFileAlterationObserver.addListener(new AdvancedFileAlterationListener(syncedFolder,
|
||||
getResources().getBoolean(R.bool.syncedFolder_light)));
|
||||
monitor.addObserver(advancedFileAlterationObserver);
|
||||
} catch (Exception e) {
|
||||
Log_OC.d(TAG, "Failed getting an observer to initialize");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
public class SyncedFolderObserverBinder extends Binder {
|
||||
public SyncedFolderObserverService getService() {
|
||||
return SyncedFolderObserverService.this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue