localPathsToUpload = new HashSet<>();
+
+ String likeParam = localPath + "%";
+
+ Cursor cursor = contentResolver.query(
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ null,
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " LIKE ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER + " = ?",
+ new String[]{likeParam, syncedFolderId, "0", "0"},
+ null);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ do {
+ String value = cursor.getString(cursor.getColumnIndex(
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
+ if (value == null) {
+ Log_OC.e(TAG, "Cannot get local path");
+ } else {
+ localPathsToUpload.add(value);
+ }
+ } while (cursor.moveToNext());
+
+ cursor.close();
+ }
+
+ return localPathsToUpload;
+ }
+
+ public void storeOrUpdateFileValue(String localPath, long modifiedAt, boolean isFolder, SyncedFolder syncedFolder) {
+
+ FileSystemDataSet data = getFilesystemDataSet(localPath, syncedFolder);
+
+ int isFolderValue = 0;
+ if (isFolder) {
+ isFolderValue = 1;
+ }
+
+ ContentValues cv = new ContentValues();
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY, System.currentTimeMillis());
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED, modifiedAt);
+
+ if (data == null) {
+
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH, localPath);
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER, isFolderValue);
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, false);
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID, syncedFolder.getId());
+
+ Uri result = contentResolver.insert(ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM, cv);
+
+ if (result == null) {
+ Log_OC.v(TAG, "Failed to insert filesystem data with local path: " + localPath);
+ }
+ } else {
+
+ if (data.getModifiedAt() != modifiedAt) {
+ cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, 0);
+ }
+
+
+ int result = contentResolver.update(
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ cv,
+ ProviderMeta.ProviderTableMeta._ID + "=?",
+ new String[]{String.valueOf(data.getId())}
+ );
+
+ if (result == 0) {
+ Log_OC.v(TAG, "Failed to update filesystem data with local path: " + localPath);
+ }
+ }
+ }
+
+ private FileSystemDataSet getFilesystemDataSet(String localPathParam, SyncedFolder syncedFolder) {
+
+ Cursor cursor = contentResolver.query(
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ null,
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
+ new String[]{localPathParam, Long.toString(syncedFolder.getId())},
+ null
+ );
+
+ FileSystemDataSet dataSet = null;
+ if (cursor != null) {
+ if (cursor.moveToFirst()) {
+ int id = cursor.getInt(cursor.getColumnIndex(ProviderMeta.ProviderTableMeta._ID));
+ String localPath = cursor.getString(cursor.getColumnIndex(
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
+ long modifiedAt = cursor.getLong(cursor.getColumnIndex(
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED));
+ boolean isFolder = false;
+ if (cursor.getInt(cursor.getColumnIndex(
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER)) != 0) {
+ isFolder = true;
+ }
+ long foundAt = cursor.getLong(cursor.getColumnIndex(ProviderMeta.
+ ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY));
+
+ boolean isSentForUpload = false;
+ if (cursor.getInt(cursor.getColumnIndex(
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD)) != 0) {
+ isSentForUpload = true;
+ }
+
+ if (id == -1) {
+ Log_OC.e(TAG, "Arbitrary value could not be created from cursor");
+ } else {
+ dataSet = new FileSystemDataSet(id, localPath, modifiedAt, isFolder, isSentForUpload, foundAt,
+ syncedFolder.getId());
+ }
+ }
+ cursor.close();
+ } else {
+ Log_OC.e(TAG, "DB error restoring arbitrary values.");
+ }
+
+ return dataSet;
+ }
+}
diff --git a/src/main/java/com/owncloud/android/datamodel/MediaFolder.java b/src/main/java/com/owncloud/android/datamodel/MediaFolder.java
index e3e29861db4a..b2655e0b557f 100644
--- a/src/main/java/com/owncloud/android/datamodel/MediaFolder.java
+++ b/src/main/java/com/owncloud/android/datamodel/MediaFolder.java
@@ -4,17 +4,17 @@
* @author Andy Scherzinger
* Copyright (C) 2016 Andy Scherzinger
* 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 .
*/
@@ -38,4 +38,7 @@ public class MediaFolder {
/** total number of files in the media folder. */
public long numberOfFiles;
+
+ /** type of media folder. */
+ public MediaFolderType type;
}
diff --git a/src/main/java/com/owncloud/android/datamodel/MediaFolderType.java b/src/main/java/com/owncloud/android/datamodel/MediaFolderType.java
new file mode 100644
index 000000000000..2a8b30a57290
--- /dev/null
+++ b/src/main/java/com/owncloud/android/datamodel/MediaFolderType.java
@@ -0,0 +1,53 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Andy Scherzinger
+ * Copyright (C) 2017 Andy Scherzinger
+ *
+ * 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.datamodel;
+
+import android.util.SparseArray;
+
+/**
+ * Types of media folder.
+ */
+public enum MediaFolderType {
+ CUSTOM(0),
+ IMAGE(1),
+ VIDEO(2);
+
+ private Integer id;
+
+ private static SparseArray reverseMap = new SparseArray<>(3);
+
+ static {
+ reverseMap.put(CUSTOM.getId(), CUSTOM);
+ reverseMap.put(IMAGE.getId(), IMAGE);
+ reverseMap.put(VIDEO.getId(), VIDEO);
+ }
+
+ MediaFolderType(Integer id) {
+ this.id = id;
+ }
+
+ public static MediaFolderType getById(Integer id) {
+ return reverseMap.get(id);
+ }
+
+ public Integer getId() {
+ return id;
+ }
+}
diff --git a/src/main/java/com/owncloud/android/datamodel/MediaProvider.java b/src/main/java/com/owncloud/android/datamodel/MediaProvider.java
index 4bc356dd43c4..4395d8f44493 100644
--- a/src/main/java/com/owncloud/android/datamodel/MediaProvider.java
+++ b/src/main/java/com/owncloud/android/datamodel/MediaProvider.java
@@ -40,6 +40,8 @@
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.Nullable;
+
/**
* Media queries to gain access to media lists for the device.
*/
@@ -47,12 +49,15 @@ public class MediaProvider {
private static final String TAG = MediaProvider.class.getSimpleName();
// fixed query parameters
- private static final Uri MEDIA_URI = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ private static final Uri IMAGES_MEDIA_URI = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
private static final String[] FILE_PROJECTION = new String[]{MediaStore.MediaColumns.DATA};
- private static final String FILE_SELECTION = MediaStore.Images.Media.BUCKET_ID + "=";
- private static final String[] FOLDER_PROJECTION = { "Distinct " + MediaStore.Images.Media.BUCKET_ID,
- MediaStore.Images.Media.BUCKET_DISPLAY_NAME };
- private static final String FOLDER_SORT_ORDER = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " ASC";
+ private static final String IMAGES_FILE_SELECTION = MediaStore.Images.Media.BUCKET_ID + "=";
+ private static final String[] IMAGES_FOLDER_PROJECTION = {"Distinct " + MediaStore.Images.Media.BUCKET_ID,
+ MediaStore.Images.Media.BUCKET_DISPLAY_NAME};
+ private static final String IMAGES_FOLDER_SORT_ORDER = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " ASC";
+
+ private static final String[] VIDEOS_FOLDER_PROJECTION = {"Distinct " + MediaStore.Video.Media.BUCKET_ID,
+ MediaStore.Video.Media.BUCKET_DISPLAY_NAME};
/**
* Getting All Images Paths.
@@ -61,11 +66,105 @@ public class MediaProvider {
* @param itemLimit the number of media items (usually images) to be returned per media folder.
* @return list with media folders
*/
- public static List getMediaFolders(ContentResolver contentResolver, int itemLimit,
- final Activity activity) {
+ public static List getImageFolders(ContentResolver contentResolver, int itemLimit,
+ @Nullable final Activity activity) {
// check permissions
- if (!PermissionUtil.checkSelfPermission(activity.getApplicationContext(),
+ checkPermissions(activity);
+
+
+ // query media/image folders
+ Cursor cursorFolders;
+ if (activity != null && PermissionUtil.checkSelfPermission(activity.getApplicationContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ cursorFolders = contentResolver.query(
+ IMAGES_MEDIA_URI,
+ IMAGES_FOLDER_PROJECTION,
+ null,
+ null,
+ IMAGES_FOLDER_SORT_ORDER
+ );
+ } else {
+ cursorFolders = contentResolver.query(
+ IMAGES_MEDIA_URI,
+ IMAGES_FOLDER_PROJECTION,
+ null,
+ null,
+ IMAGES_FOLDER_SORT_ORDER
+ );
+ }
+ List mediaFolders = new ArrayList<>();
+ String dataPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder();
+
+ if (cursorFolders != null) {
+ String folderName;
+ String fileSortOrder = MediaStore.Images.Media.DATE_TAKEN + " DESC LIMIT " + itemLimit;
+ Cursor cursorImages;
+
+ while (cursorFolders.moveToNext()) {
+ String folderId = cursorFolders.getString(cursorFolders.getColumnIndex(MediaStore.Images.Media
+ .BUCKET_ID));
+
+ MediaFolder mediaFolder = new MediaFolder();
+ folderName = cursorFolders.getString(cursorFolders.getColumnIndex(
+ MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
+ mediaFolder.type = MediaFolderType.IMAGE;
+ mediaFolder.folderName = folderName;
+ mediaFolder.filePaths = new ArrayList<>();
+
+ // query images
+ cursorImages = contentResolver.query(
+ IMAGES_MEDIA_URI,
+ FILE_PROJECTION,
+ IMAGES_FILE_SELECTION + folderId,
+ null,
+ fileSortOrder
+ );
+ Log.d(TAG, "Reading images for " + mediaFolder.folderName);
+
+ if (cursorImages != null) {
+ String filePath;
+
+ while (cursorImages.moveToNext()) {
+ filePath = cursorImages.getString(cursorImages.getColumnIndexOrThrow(
+ MediaStore.MediaColumns.DATA));
+
+ if (filePath != null) {
+ mediaFolder.filePaths.add(filePath);
+ mediaFolder.absolutePath = filePath.substring(0, filePath.lastIndexOf("/"));
+ }
+ }
+ cursorImages.close();
+
+ // only do further work if folder is not within the Nextcloud app itself
+ if (!mediaFolder.absolutePath.startsWith(dataPath)) {
+
+ // count images
+ Cursor count = contentResolver.query(
+ IMAGES_MEDIA_URI,
+ FILE_PROJECTION,
+ IMAGES_FILE_SELECTION + folderId,
+ null,
+ null);
+
+ if (count != null) {
+ mediaFolder.numberOfFiles = count.getCount();
+ count.close();
+ }
+
+ mediaFolders.add(mediaFolder);
+ }
+ }
+ }
+ cursorFolders.close();
+ }
+
+ return mediaFolders;
+ }
+
+ private static void checkPermissions(@Nullable Activity activity) {
+ if (activity != null &&
+ !PermissionUtil.checkSelfPermission(activity.getApplicationContext(),
+ Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Check if we should show an explanation
if (PermissionUtil.shouldShowRequestPermissionRationale(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
@@ -87,49 +186,46 @@ public void onClick(View v) {
PermissionUtil.requestWriteExternalStoreagePermission(activity);
}
}
+ }
- // query media/image folders
- Cursor cursorFolders = null;
- if (PermissionUtil.checkSelfPermission(activity.getApplicationContext(),
- Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- cursorFolders = contentResolver.query(MEDIA_URI, FOLDER_PROJECTION, null, null, FOLDER_SORT_ORDER);
- }
+ public static List getVideoFolders(ContentResolver contentResolver, int itemLimit) {
+ Cursor cursorFolders = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ VIDEOS_FOLDER_PROJECTION, null, null, null);
List mediaFolders = new ArrayList<>();
String dataPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder();
if (cursorFolders != null) {
String folderName;
- String fileSortOrder = MediaStore.Images.Media.DATE_TAKEN + " DESC LIMIT " + itemLimit;
+ String fileSortOrder = MediaStore.Video.Media.DATE_TAKEN + " DESC LIMIT " + itemLimit;
Cursor cursorImages;
while (cursorFolders.moveToNext()) {
- String folderId = cursorFolders.getString(cursorFolders.getColumnIndex(MediaStore.Images.Media
+ String folderId = cursorFolders.getString(cursorFolders.getColumnIndex(MediaStore.Video.Media
.BUCKET_ID));
MediaFolder mediaFolder = new MediaFolder();
folderName = cursorFolders.getString(cursorFolders.getColumnIndex(
- MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
+ MediaStore.Video.Media.BUCKET_DISPLAY_NAME));
+ mediaFolder.type = MediaFolderType.VIDEO;
mediaFolder.folderName = folderName;
mediaFolder.filePaths = new ArrayList<>();
// query images
- cursorImages = contentResolver.query(MEDIA_URI, FILE_PROJECTION, FILE_SELECTION + folderId, null,
+ cursorImages = contentResolver.query(
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ FILE_PROJECTION,
+ MediaStore.Video.Media.BUCKET_ID + "=" + folderId,
+ null,
fileSortOrder);
- Log.d(TAG, "Reading images for " + mediaFolder.folderName);
+ Log.d(TAG, "Reading videos for " + mediaFolder.folderName);
if (cursorImages != null) {
String filePath;
- int failedImages = 0;
while (cursorImages.moveToNext()) {
filePath = cursorImages.getString(cursorImages.getColumnIndexOrThrow(
MediaStore.MediaColumns.DATA));
-
- if (filePath != null) {
- mediaFolder.filePaths.add(filePath);
- mediaFolder.absolutePath = filePath.substring(0, filePath.lastIndexOf("/"));
- } else {
- failedImages++;
- }
+ mediaFolder.filePaths.add(filePath);
+ mediaFolder.absolutePath = filePath.substring(0, filePath.lastIndexOf("/"));
}
cursorImages.close();
@@ -138,14 +234,14 @@ public void onClick(View v) {
// count images
Cursor count = contentResolver.query(
- MEDIA_URI,
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
FILE_PROJECTION,
- FILE_SELECTION + folderId,
+ MediaStore.Video.Media.BUCKET_ID + "=" + folderId,
null,
null);
if (count != null) {
- mediaFolder.numberOfFiles = count.getCount() - failedImages;
+ mediaFolder.numberOfFiles = count.getCount();
count.close();
}
diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java
index a491d993a612..4ba9038d7fb4 100644
--- a/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java
+++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java
@@ -26,7 +26,7 @@
/**
* Synced folder entity containing all information per synced folder.
*/
-public class SyncedFolder implements Serializable {
+public class SyncedFolder implements Serializable, Cloneable {
public static final long UNPERSISTED_ID = Long.MIN_VALUE;
private static final long serialVersionUID = -793476118299906429L;
private long id = UNPERSISTED_ID;
@@ -38,6 +38,7 @@ public class SyncedFolder implements Serializable {
private String account;
private Integer uploadAction;
private boolean enabled;
+ private MediaFolderType type;
/**
* constructor for already persisted entity.
@@ -51,9 +52,11 @@ public class SyncedFolder implements Serializable {
* @param account the account owning the synced folder
* @param uploadAction the action to be done after the upload
* @param enabled flag if synced folder config is active
+ * @param type the type of the folder
*/
public SyncedFolder(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
- Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled) {
+ Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
+ MediaFolderType type) {
this.id = id;
this.localPath = localPath;
this.remotePath = remotePath;
@@ -63,6 +66,7 @@ public SyncedFolder(long id, String localPath, String remotePath, Boolean wifiOn
this.account = account;
this.uploadAction = uploadAction;
this.enabled = enabled;
+ this.type = type;
}
/**
@@ -76,9 +80,11 @@ public SyncedFolder(long id, String localPath, String remotePath, Boolean wifiOn
* @param account the account owning the synced folder
* @param uploadAction the action to be done after the upload
* @param enabled flag if synced folder config is active
+ * @param type the type of the folder
*/
public SyncedFolder(String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
- Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled) {
+ Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
+ MediaFolderType type) {
this.localPath = localPath;
this.remotePath = remotePath;
this.wifiOnly = wifiOnly;
@@ -87,6 +93,15 @@ public SyncedFolder(String localPath, String remotePath, Boolean wifiOnly, Boole
this.account = account;
this.uploadAction = uploadAction;
this.enabled = enabled;
+ this.type = type;
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
}
public long getId() {
@@ -160,4 +175,12 @@ public boolean isEnabled() {
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
+
+ public MediaFolderType getType() {
+ return type;
+ }
+
+ public void setType(MediaFolderType type) {
+ this.type = type;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java
index 5ee7e90bef4d..f0cfebc21e97 100644
--- a/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java
+++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java
@@ -47,11 +47,13 @@ public class SyncedFolderDisplayItem extends SyncedFolder {
* @param filePaths the UI info for the file path
* @param folderName the UI info for the folder's name
* @param numberOfFiles the UI info for number of files within the folder
+ * @param type the type of the folder
*/
public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boolean wifiOnly, Boolean chargingOnly,
Boolean subfolderByDate, String account, Integer uploadAction, Boolean enabled,
- List filePaths, String folderName, long numberOfFiles) {
- super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled);
+ List filePaths, String folderName, long numberOfFiles, MediaFolderType type)
+ {
+ super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, type);
this.filePaths = filePaths;
this.folderName = folderName;
this.numberOfFiles = numberOfFiles;
@@ -59,12 +61,11 @@ public SyncedFolderDisplayItem(long id, String localPath, String remotePath, Boo
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);
+ String folderName, MediaFolderType type) {
+ super(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate, account, uploadAction, enabled, type);
this.folderName = folderName;
}
-
public List getFilePaths() {
return filePaths;
}
diff --git a/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java b/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java
index ee3b1762c708..a9e4d5ea6dc4 100644
--- a/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java
+++ b/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java
@@ -1,21 +1,22 @@
/**
- * Nextcloud Android client application
+ * Nextcloud Android client application
*
- * Copyright (C) 2016 Andy Scherzinger
- * Copyright (C) 2016 Nextcloud.
+ * @author Andy Scherzinger
+ * Copyright (C) 2016 Andy Scherzinger
+ * 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 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.
+ * 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 .
+ * 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;
@@ -27,7 +28,6 @@
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;
@@ -58,12 +58,12 @@ public SyncedFolderProvider(ContentResolver contentResolver) {
}
/**
- * Stores an media folder sync object in database.
+ * Stores a synced folder object in database.
*
* @param syncedFolder synced folder to store
* @return synced folder id, -1 if the insert process fails.
*/
- public long storeFolderSync(SyncedFolder syncedFolder) {
+ public long storeSyncedFolder(SyncedFolder syncedFolder) {
Log_OC.v(TAG, "Inserting " + syncedFolder.getLocalPath() + " with enabled=" + syncedFolder.isEnabled());
ContentValues cv = createContentValuesFromSyncedFolder(syncedFolder);
@@ -71,7 +71,6 @@ public long storeFolderSync(SyncedFolder syncedFolder) {
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.");
@@ -118,12 +117,12 @@ public List getSyncedFolders() {
/**
* Update upload status of file uniquely referenced by id.
*
- * @param id folder sync id.
+ * @param id synced folder id.
* @param enabled new status.
* @return the number of rows updated.
*/
- public int updateFolderSyncEnabled(long id, Boolean enabled) {
- Log_OC.v(TAG, "Storing sync folder id" + id + " with enabled=" + enabled);
+ public int updateSyncedFolderEnabled(long id, Boolean enabled) {
+ Log_OC.v(TAG, "Storing synced folder id" + id + " with enabled=" + enabled);
int result = 0;
Cursor cursor = mContentResolver.query(
@@ -187,7 +186,6 @@ public SyncedFolder findByLocalPath(String localPath) {
}
return result;
-
}
/**
@@ -211,15 +209,12 @@ public int deleteSyncFoldersForAccount(Account account) {
*
* @param id for the synced folder.
*/
-
private int deleteSyncFolderWithId(long id) {
- int result = mContentResolver.delete(
+ return mContentResolver.delete(
ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS,
ProviderMeta.ProviderTableMeta._ID + " = ?",
new String[]{String.valueOf(id)}
);
-
- return result;
}
@@ -274,6 +269,17 @@ public int deleteSyncedFoldersNotInList(Context context, ArrayList ids) {
return result;
}
+ /**
+ * delete record of synchronized folder with the given id.
+ */
+ public int deleteSyncedFolder(long id) {
+ return mContentResolver.delete(
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS,
+ ProviderMeta.ProviderTableMeta._ID + " = ?",
+ new String[]{String.valueOf(id)}
+ );
+ }
+
/**
* update given synced folder.
*
@@ -292,10 +298,6 @@ public int updateSyncFolder(SyncedFolder syncedFolder) {
new String[]{String.valueOf(syncedFolder.getId())}
);
- if (result > 0) {
- notifyFolderSyncObservers(syncedFolder);
- }
-
return result;
}
@@ -325,9 +327,11 @@ private SyncedFolder createSyncedFolderFromCursor(Cursor cursor) {
ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION));
Boolean enabled = cursor.getInt(cursor.getColumnIndex(
ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED)) == 1;
+ MediaFolderType type = MediaFolderType.getById(cursor.getInt(cursor.getColumnIndex(
+ ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE)));
syncedFolder = new SyncedFolder(id, localPath, remotePath, wifiOnly, chargingOnly, subfolderByDate,
- accountName, uploadAction, enabled);
+ accountName, uploadAction, enabled, type);
}
return syncedFolder;
}
@@ -349,18 +353,8 @@ private ContentValues createContentValuesFromSyncedFolder(SyncedFolder syncedFol
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE, syncedFolder.getSubfolderByDate());
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT, syncedFolder.getAccount());
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION, syncedFolder.getUploadAction());
- return cv;
- }
+ cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE, syncedFolder.getType().getId());
- /**
- * 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());
- }
+ return cv;
}
}
diff --git a/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
index a9ceadc77472..7ed0a3a8bd8c 100644
--- a/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
+++ b/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
@@ -30,6 +30,7 @@
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.media.MediaMetadataRetriever;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.AsyncTask;
@@ -418,6 +419,7 @@ private Bitmap doFileInBackground() {
}
public static class MediaThumbnailGenerationTask extends AsyncTask {
+ private enum Type {IMAGE, VIDEO}
private final WeakReference mImageViewReference;
private File mFile;
private String mImageKey = null;
@@ -439,7 +441,9 @@ protected Bitmap doInBackground(Object... params) {
}
if (MimeTypeUtil.isImage(mFile)) {
- thumbnail = doFileInBackground(mFile);
+ thumbnail = doFileInBackground(mFile, Type.IMAGE);
+ } else if (MimeTypeUtil.isVideo(mFile)) {
+ thumbnail = doFileInBackground(mFile, Type.VIDEO);
}
}
} // the app should never break due to a problem with thumbnails
@@ -482,7 +486,7 @@ protected void onPostExecute(Bitmap bitmap) {
}
}
- private Bitmap doFileInBackground(File file) {
+ private Bitmap doFileInBackground(File file, Type type) {
final String imageKey;
if (mImageKey != null) {
@@ -497,14 +501,45 @@ private Bitmap doFileInBackground(File file) {
// Not found in disk cache
if (thumbnail == null) {
- int px = getThumbnailDimension();
+ if (Type.IMAGE.equals(type)) {
+ int px = getThumbnailDimension();
- Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), px, px);
+ Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), px, px);
- if (bitmap != null) {
- thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px);
+ if (bitmap != null) {
+ thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px);
+ }
+ } else if (Type.VIDEO.equals(type)) {
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ try {
+ retriever.setDataSource(file.getAbsolutePath());
+ thumbnail = retriever.getFrameAtTime(-1);
+ } catch (Exception ex) {
+ // can't create a bitmap
+ Log_OC.w(TAG, "Failed to create bitmap from video " + file.getAbsolutePath());
+ } finally {
+ try {
+ retriever.release();
+ } catch (RuntimeException ex) {
+ // Ignore failure at this point.
+ Log_OC.w(TAG, "Failed release MediaMetadataRetriever for " + file.getAbsolutePath());
+ }
+ }
+
+ if (thumbnail != null) {
+ // Scale down bitmap if too large.
+ int px = getThumbnailDimension();
+ int width = thumbnail.getWidth();
+ int height = thumbnail.getHeight();
+ int max = Math.max(width, height);
+ if (max > px) {
+ thumbnail = BitmapUtils.scaleBitmap(thumbnail, px, width, height, max);
+ thumbnail = addThumbnailToCache(imageKey, thumbnail, file.getPath(), px);
+ }
+ }
}
}
+
return thumbnail;
}
}
diff --git a/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
index 9d4a7608b7bc..4ddc20914503 100644
--- a/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
+++ b/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
@@ -1,22 +1,22 @@
/**
- * ownCloud Android client application
+ * ownCloud Android client application
*
- * @author LukeOwncloud
- * @author David A. Velasco
- * @author masensio
- * Copyright (C) 2016 ownCloud Inc.
+ * @author LukeOwncloud
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2016 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 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.
+ * 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 .
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*/
package com.owncloud.android.datamodel;
@@ -26,12 +26,8 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Build;
-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;
import com.owncloud.android.db.UploadResult;
@@ -39,14 +35,9 @@
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.operations.UploadFileOperation;
-import com.owncloud.android.services.AutoUploadJob;
-import java.util.ArrayList;
import java.util.Calendar;
-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
@@ -130,6 +121,8 @@ public long storeUpload(OCUpload ocUpload) {
cv.put(ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER, ocUpload.isCreateRemoteFolder() ? 1 : 0);
cv.put(ProviderTableMeta.UPLOADS_LAST_RESULT, ocUpload.getLastResult().getValue());
cv.put(ProviderTableMeta.UPLOADS_CREATED_BY, ocUpload.getCreadtedBy());
+ cv.put(ProviderTableMeta.UPLOADS_IS_WHILE_CHARGING_ONLY, ocUpload.isWhileChargingOnly() ? 1 : 0);
+ cv.put(ProviderTableMeta.UPLOADS_IS_WIFI_ONLY, ocUpload.isUseWifiOnly() ? 1 : 0);
Uri result = getDB().insert(ProviderTableMeta.CONTENT_URI_UPLOADS, cv);
@@ -163,9 +156,9 @@ public int updateUpload(OCUpload ocUpload) {
cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, ocUpload.getUploadEndTimestamp());
int result = getDB().update(ProviderTableMeta.CONTENT_URI_UPLOADS,
- cv,
- ProviderTableMeta._ID + "=?",
- new String[]{String.valueOf(ocUpload.getUploadId())}
+ cv,
+ ProviderTableMeta._ID + "=?",
+ new String[]{String.valueOf(ocUpload.getUploadId())}
);
Log_OC.d(TAG, "updateUpload returns with: " + result + " for file: " + ocUpload.getLocalPath());
@@ -188,15 +181,15 @@ private int updateUploadInternal(Cursor c, UploadStatus status, UploadResult res
String path = c.getString(c.getColumnIndex(ProviderTableMeta.UPLOADS_LOCAL_PATH));
Log_OC.v(
- TAG,
- "Updating " + path + " with status:" + status + " and result:"
- + (result == null ? "null" : result.toString()) + " (old:"
- + upload.toFormattedString() + ")");
+ TAG,
+ "Updating " + path + " with status:" + status + " and result:"
+ + (result == null ? "null" : result.toString()) + " (old:"
+ + upload.toFormattedString() + ")");
upload.setUploadStatus(status);
upload.setLastResult(result);
upload.setRemotePath(remotePath);
- if(localPath != null) {
+ if (localPath != null) {
upload.setLocalPath(localPath);
}
if (status == UploadStatus.UPLOAD_SUCCEEDED) {
@@ -221,7 +214,7 @@ private int updateUploadInternal(Cursor c, UploadStatus status, UploadResult res
* @param localPath path of the file to upload in the device storage
* @return 1 if file status was updated, else 0.
*/
- public int updateUploadStatus(long id, UploadStatus status, UploadResult result, String remotePath,
+ private int updateUploadStatus(long id, UploadStatus status, UploadResult result, String remotePath,
String localPath) {
//Log_OC.v(TAG, "Updating "+filepath+" with uploadStatus="+status +" and result="+result);
@@ -236,7 +229,7 @@ public int updateUploadStatus(long id, UploadStatus status, UploadResult result,
if (c.getCount() != 1) {
Log_OC.e(TAG, c.getCount() + " items for id=" + id
- + " available in UploadDb. Expected 1. Failed to update upload db.");
+ + " available in UploadDb. Expected 1. Failed to update upload db.");
} else {
returnValue = updateUploadInternal(c, status, result, remotePath, localPath);
}
@@ -266,7 +259,7 @@ public void notifyObserversNow() {
public int removeUpload(OCUpload upload) {
int result = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
- ProviderTableMeta._ID + "=?" ,
+ ProviderTableMeta._ID + "=?",
new String[]{Long.toString(upload.getUploadId())}
);
Log_OC.d(TAG, "delete returns " + result + " for upload " + upload);
@@ -287,7 +280,7 @@ public int removeUpload(OCUpload upload) {
public int removeUpload(String accountName, String remotePath) {
int result = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
- ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=? AND " + ProviderTableMeta.UPLOADS_REMOTE_PATH + "=?" ,
+ ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=? AND " + ProviderTableMeta.UPLOADS_REMOTE_PATH + "=?",
new String[]{accountName, remotePath}
);
Log_OC.d(TAG, "delete returns " + result + " for file " + remotePath + " in " + accountName);
@@ -374,68 +367,21 @@ private OCUpload createOCUploadFromCursor(Cursor c) {
return upload;
}
- /**
- * Get all uploads which are currently being uploaded or waiting in the queue to be uploaded.
- */
- public OCUpload[] getCurrentAndPendingUploads() {
+ public OCUpload[] getCurrentAndPendingUploadsForCurrentAccount() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
OCUpload[] uploads = getUploads(
- 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(),
- null
+ ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
+ " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+ " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.LOCK_FAILED.getValue() +
+ " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
+ "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+ " AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+ new String[]{account.name}
);
- // add pending Jobs
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- return uploads;
- } else {
- List result = getPendingJobs();
- Collections.addAll(result, uploads);
- return result.toArray(uploads);
- }
- }
-
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
- private List getPendingJobs() {
- Set jobRequests = JobManager.create(mContext).getAllJobRequestsForTag(AutoUploadJob.TAG);
-
- ArrayList list = new ArrayList<>();
-
- for (JobRequest ji : jobRequests) {
- PersistableBundleCompat extras = ji.getExtras();
- OCUpload upload = new OCUpload(extras.getString("filePath", ""),
- extras.getString("remotePath", ""),
- extras.getString("account", ""));
-
- list.add(upload);
- }
-
- return list;
- }
+ return uploads;
- public void cancelPendingAutoUploadJobsForAccount(Account account) {
- JobManager jobManager = JobManager.create(mContext);
- for (JobRequest ji: jobManager.getAllJobRequestsForTag(AutoUploadJob.TAG)) {
- if (ji.getExtras().getString(AutoUploadJob.ACCOUNT, "").equalsIgnoreCase(account.name)) {
- jobManager.cancel(ji.getJobId());
- }
- }
- }
-
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
- public void cancelPendingJob(String accountName, String remotePath){
- 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;
- }
- }
}
/**
@@ -447,6 +393,13 @@ public OCUpload[] getFailedUploads() {
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value, null);
}
+ public OCUpload[] getFinishedUploadsForCurrentAccount() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
+
+ return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
+ ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{account.name});
+ }
+
/**
* Get all uploads which where successfully completed.
*/
@@ -455,16 +408,33 @@ public OCUpload[] getFinishedUploads() {
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value, null);
}
+ public OCUpload[] getFailedButNotDelayedUploadsForCurrentAccount() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
+
+ return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+ AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+ new String[]{account.name}
+ );
+ }
+
/**
- * Get all failed uploads, except for those that were not performed due to lack of Wifi connection
- * @return Array of failed uploads, except for those that were not performed due to lack of Wifi connection.
+ * Get all failed uploads, except for those that were not performed due to lack of Wifi connection.
+ *
+ * @return Array of failed uploads, except for those that were not performed due to lack of Wifi connection.
*/
public OCUpload[] getFailedButNotDelayedUploads() {
return getUploads(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
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() + AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(),
+ null
);
}
@@ -473,13 +443,22 @@ private ContentResolver getDB() {
}
public long clearFailedButNotDelayedUploads() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
+
long result = getDB().delete(
- ProviderTableMeta.CONTENT_URI_UPLOADS,
- 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
+ ProviderTableMeta.CONTENT_URI_UPLOADS,
+ ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+ new String[]{account.name}
);
+
Log_OC.d(TAG, "delete all failed uploads but those delayed for Wifi");
if (result > 0) {
notifyObserversNow();
@@ -488,11 +467,14 @@ public long clearFailedButNotDelayedUploads() {
}
public long clearSuccessfulUploads() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
long result = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
- ProviderTableMeta.UPLOADS_STATUS + "=="+ UploadStatus.UPLOAD_SUCCEEDED.value, null
+ ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
+ ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{account.name}
);
+
Log_OC.d(TAG, "delete all successful uploads");
if (result > 0) {
notifyObserversNow();
@@ -501,21 +483,31 @@ public long clearSuccessfulUploads() {
}
public long clearAllFinishedButNotDelayedUploads() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
- String[] whereArgs = new String[2];
+ String[] whereArgs = new String[3];
whereArgs[0] = String.valueOf(UploadStatus.UPLOAD_SUCCEEDED.value);
whereArgs[1] = String.valueOf(UploadStatus.UPLOAD_FAILED.value);
+ whereArgs[2] = account.name;
long result = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
- 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(),
+ ProviderTableMeta.UPLOADS_STATUS + "=? OR " + ProviderTableMeta.UPLOADS_STATUS + "=?" +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+ AND +
+ ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
whereArgs
);
+
Log_OC.d(TAG, "delete all finished uploads");
if (result > 0) {
notifyObserversNow();
}
+
return result;
}
@@ -528,28 +520,28 @@ public void updateDatabaseUploadResult(RemoteOperationResult uploadResult, Uploa
if (uploadResult.isCancelled()) {
removeUpload(
- upload.getAccount().name,
- upload.getRemotePath()
+ upload.getAccount().name,
+ upload.getRemotePath()
);
} else {
String localPath = (FileUploader.LOCAL_BEHAVIOUR_MOVE == upload.getLocalBehaviour())
- ? upload.getStoragePath() : null;
+ ? upload.getStoragePath() : null;
if (uploadResult.isSuccess()) {
updateUploadStatus(
- upload.getOCUploadId(),
- UploadStatus.UPLOAD_SUCCEEDED,
- UploadResult.UPLOADED,
- upload.getRemotePath(),
- localPath
+ upload.getOCUploadId(),
+ UploadStatus.UPLOAD_SUCCEEDED,
+ UploadResult.UPLOADED,
+ upload.getRemotePath(),
+ localPath
);
} else {
updateUploadStatus(
- upload.getOCUploadId(),
- UploadStatus.UPLOAD_FAILED,
- UploadResult.fromOperationResult(uploadResult),
- upload.getRemotePath(),
- localPath
+ upload.getOCUploadId(),
+ UploadStatus.UPLOAD_FAILED,
+ UploadResult.fromOperationResult(uploadResult),
+ upload.getRemotePath(),
+ localPath
);
}
}
@@ -560,14 +552,14 @@ public void updateDatabaseUploadResult(RemoteOperationResult uploadResult, Uploa
*/
public void updateDatabaseUploadStart(UploadFileOperation upload) {
String localPath = (FileUploader.LOCAL_BEHAVIOUR_MOVE == upload.getLocalBehaviour())
- ? upload.getStoragePath() : null;
+ ? upload.getStoragePath() : null;
updateUploadStatus(
- upload.getOCUploadId(),
- UploadStatus.UPLOAD_IN_PROGRESS,
- UploadResult.UNKNOWN,
- upload.getRemotePath(),
- localPath
+ upload.getOCUploadId(),
+ UploadStatus.UPLOAD_IN_PROGRESS,
+ UploadResult.UNKNOWN,
+ upload.getRemotePath(),
+ localPath
);
}
@@ -576,7 +568,7 @@ public void updateDatabaseUploadStart(UploadFileOperation upload) {
* Changes the status of any in progress upload from UploadStatus.UPLOAD_IN_PROGRESS
* to UploadStatus.UPLOAD_FAILED
*
- * @return Number of uploads which status was changed.
+ * @return Number of uploads which status was changed.
*/
public int failInProgressUploads(UploadResult fail) {
Log_OC.v(TAG, "Updating state of any killed upload");
@@ -584,16 +576,16 @@ public int failInProgressUploads(UploadResult fail) {
ContentValues cv = new ContentValues();
cv.put(ProviderTableMeta.UPLOADS_STATUS, UploadStatus.UPLOAD_FAILED.getValue());
cv.put(
- ProviderTableMeta.UPLOADS_LAST_RESULT,
- fail != null ? fail.getValue() : UploadResult.UNKNOWN.getValue()
+ ProviderTableMeta.UPLOADS_LAST_RESULT,
+ fail != null ? fail.getValue() : UploadResult.UNKNOWN.getValue()
);
cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, Calendar.getInstance().getTimeInMillis());
int result = getDB().update(
- ProviderTableMeta.CONTENT_URI_UPLOADS,
- cv,
- ProviderTableMeta.UPLOADS_STATUS + "=?",
- new String[]{String.valueOf(UploadStatus.UPLOAD_IN_PROGRESS.getValue())}
+ ProviderTableMeta.CONTENT_URI_UPLOADS,
+ cv,
+ ProviderTableMeta.UPLOADS_STATUS + "=?",
+ new String[]{String.valueOf(UploadStatus.UPLOAD_IN_PROGRESS.getValue())}
);
if (result == 0) {
@@ -602,15 +594,7 @@ public int failInProgressUploads(UploadResult fail) {
Log_OC.w(TAG, Integer.toString(result) + " uploads where abruptly interrupted");
notifyObserversNow();
}
- return result;
- }
- public int removeAccountUploads(Account account) {
- Log_OC.v(TAG, "Delete all uploads for account " + account.name);
- return getDB().delete(
- ProviderTableMeta.CONTENT_URI_UPLOADS,
- ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=?",
- new String[]{account.name});
+ return result;
}
-
}
diff --git a/src/main/java/com/owncloud/android/db/OCUpload.java b/src/main/java/com/owncloud/android/db/OCUpload.java
index 0b78af00b2d6..962890bd031e 100644
--- a/src/main/java/com/owncloud/android/db/OCUpload.java
+++ b/src/main/java/com/owncloud/android/db/OCUpload.java
@@ -40,7 +40,6 @@
/**
* Stores all information in order to start upload operations. PersistentUploadObject can
* be stored persistently by {@link UploadsStorageManager}.
- *
*/
public class OCUpload implements Parcelable {
@@ -49,7 +48,7 @@ public class OCUpload implements Parcelable {
private long mId;
/**
- * Absolute path in the local file system to the file to be uploaded
+ * Absolute path in the local file system to the file to be uploaded.
*/
private String mLocalPath;
@@ -64,7 +63,7 @@ public class OCUpload implements Parcelable {
private String mAccountName;
/**
- * File size
+ * File size.
*/
private long mFileSize;
@@ -77,14 +76,17 @@ public class OCUpload implements Parcelable {
* Overwrite destination file?
*/
private boolean mForceOverwrite;
+
/**
* Create destination folder?
*/
private boolean mIsCreateRemoteFolder;
+
/**
* Status of upload (later, in_progress, ...).
*/
private UploadStatus mUploadStatus;
+
/**
* Result from last upload operation. Can be null.
*/
@@ -95,14 +97,23 @@ public class OCUpload implements Parcelable {
*/
private int mCreatedBy;
- /*
+ /**
* When the upload ended
*/
private long mUploadEndTimeStamp;
+ /**
+ * Upload only via wifi?
+ */
+ private boolean mIsUseWifiOnly;
/**
- * Main constructor
+ * Upload only if phone being charged?
+ */
+ private boolean mIsWhileChargingOnly;
+
+ /**
+ * Main constructor.
*
* @param localPath Absolute path in the local file system to the file to be uploaded.
* @param remotePath Absolute path in the remote account to set to the uploaded file.
@@ -124,9 +135,8 @@ public OCUpload(String localPath, String remotePath, String accountName) {
mAccountName = accountName;
}
-
/**
- * Convenience constructor to reupload already existing {@link OCFile}s
+ * Convenience constructor to reupload already existing {@link OCFile}s.
*
* @param ocFile {@link OCFile} instance to update in the remote server.
* @param account ownCloud {@link Account} where ocFile is contained.
@@ -135,7 +145,6 @@ public OCUpload(OCFile ocFile, Account account) {
this(ocFile.getStoragePath(), ocFile.getRemotePath(), account.name);
}
-
/**
* Reset all the fields to default values.
*/
@@ -151,6 +160,8 @@ private void resetData() {
mUploadStatus = UploadStatus.UPLOAD_IN_PROGRESS;
mLastResult = UploadResult.UNKNOWN;
mCreatedBy = UploadFileOperation.CREATED_BY_USER;
+ mIsUseWifiOnly = true;
+ mIsWhileChargingOnly = false;
}
// Getters & Setters
@@ -230,7 +241,6 @@ public void setFileSize(long fileSize) {
mFileSize = fileSize;
}
-
/**
* @return the mimeType
*/
@@ -340,6 +350,28 @@ public OCUpload[] newArray(int size) {
}
};
+ /**
+ * @return the isUseWifiOnly
+ */
+ public boolean isUseWifiOnly() {
+ return mIsUseWifiOnly;
+ }
+
+ /**
+ * @param isUseWifiOnly the isUseWifiOnly to set
+ */
+ public void setUseWifiOnly(boolean isUseWifiOnly) {
+ this.mIsUseWifiOnly = isUseWifiOnly;
+ }
+
+ public void setWhileChargingOnly(boolean isWhileChargingOnly) {
+ this.mIsWhileChargingOnly = isWhileChargingOnly;
+ }
+
+ public boolean isWhileChargingOnly() {
+ return mIsWhileChargingOnly;
+ }
+
/**
* Reconstruct from parcel
*
@@ -369,9 +401,10 @@ public void readFromParcel(Parcel source) {
mLastResult = UploadResult.UNKNOWN;
}
mCreatedBy = source.readInt();
+ mIsUseWifiOnly = (source.readInt() == 1);
+ mIsWhileChargingOnly = (source.readInt() == 1);
}
-
@Override
public int describeContents() {
return this.hashCode();
@@ -390,6 +423,8 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mUploadEndTimeStamp);
dest.writeString(((mLastResult == null) ? "" : mLastResult.name()));
dest.writeInt(mCreatedBy);
+ dest.writeInt(mIsUseWifiOnly ? 1 : 0);
+ dest.writeInt(mIsWhileChargingOnly ? 1 : 0);
}
enum CanUploadFileNowStatus {NOW, LATER, FILE_GONE, ERROR}
diff --git a/src/main/java/com/owncloud/android/db/PreferenceManager.java b/src/main/java/com/owncloud/android/db/PreferenceManager.java
index daff294f5913..dc7c6195f639 100644
--- a/src/main/java/com/owncloud/android/db/PreferenceManager.java
+++ b/src/main/java/com/owncloud/android/db/PreferenceManager.java
@@ -48,6 +48,8 @@ public abstract class PreferenceManager {
private static final String PREF__LEGACY_CLEAN = "legacyClean";
private static final String PREF__AUTO_UPLOAD_UPDATE_PATH = "autoUploadPathUpdate";
private static final String PREF__PUSH_TOKEN = "pushToken";
+ private static final String PREF__AUTO_UPLOAD_SPLIT_OUT = "autoUploadEntriesSplitOut";
+ private static final String PREF__AUTO_UPLOAD_INIT = "autoUploadInit";
public static void setPushToken(Context context, String pushToken) {
saveStringPreferenceNow(context, PREF__PUSH_TOKEN, pushToken);
@@ -198,6 +200,10 @@ public static void setSortAscending(Context context, boolean ascending) {
saveBooleanPreference(context, AUTO_PREF__SORT_ASCENDING, ascending);
}
+ public static boolean getAutoUploadInit(Context context) {
+ return getDefaultSharedPreferences(context).getBoolean(PREF__AUTO_UPLOAD_INIT, false);
+ }
+
/**
* Gets the legacy cleaning flag last set.
*
@@ -218,6 +224,15 @@ public static boolean getAutoUploadPathsUpdate(Context context) {
return getDefaultSharedPreferences(context).getBoolean(PREF__AUTO_UPLOAD_UPDATE_PATH, false);
}
+ /**
+ * Gets the auto upload split out flag last set.
+ *
+ * @param context Caller {@link Context}, used to access to shared preferences manager.
+ * @return ascending order the legacy cleaning flag, default is false
+ */
+ public static boolean getAutoUploadSplitEntries(Context context) {
+ return getDefaultSharedPreferences(context).getBoolean(PREF__AUTO_UPLOAD_SPLIT_OUT, false);
+ }
/**
* Saves the legacy cleaning flag which the user has set last.
@@ -229,6 +244,10 @@ public static void setLegacyClean(Context context, boolean legacyClean) {
saveBooleanPreference(context, PREF__LEGACY_CLEAN, legacyClean);
}
+ public static void setAutoUploadInit(Context context, boolean autoUploadInit) {
+ saveBooleanPreference(context, PREF__AUTO_UPLOAD_INIT, autoUploadInit);
+ }
+
/**
* Saves the legacy cleaning flag which the user has set last.
*
@@ -239,6 +258,15 @@ public static void setAutoUploadPathsUpdate(Context context, boolean pathUpdate)
saveBooleanPreference(context, PREF__AUTO_UPLOAD_UPDATE_PATH, pathUpdate);
}
+ /**
+ * Saves the flag for split entries magic
+ *
+ * @param context Caller {@link Context}, used to access to shared preferences manager.
+ * @param splitOut flag if it is a auto upload path update
+ */
+ public static void setAutoUploadSplitEntries(Context context, boolean splitOut) {
+ saveBooleanPreference(context, PREF__AUTO_UPLOAD_SPLIT_OUT, splitOut);
+ }
/**
* Gets the uploader behavior which the user has set last.
@@ -280,7 +308,7 @@ public static void setGridColumns(Context context, float gridColumns) {
saveFloatPreference(context, AUTO_PREF__GRID_COLUMNS, gridColumns);
}
- public static void saveBooleanPreference(Context context, String key, boolean value) {
+ private static void saveBooleanPreference(Context context, String key, boolean value) {
SharedPreferences.Editor appPreferences = getDefaultSharedPreferences(context.getApplicationContext()).edit();
appPreferences.putBoolean(key, value).apply();
}
@@ -301,17 +329,11 @@ private static void saveIntPreference(Context context, String key, int value) {
appPreferences.putInt(key, value).apply();
}
- public static void saveFloatPreference(Context context, String key, float value) {
+ private static void saveFloatPreference(Context context, String key, float value) {
SharedPreferences.Editor appPreferences = getDefaultSharedPreferences(context.getApplicationContext()).edit();
appPreferences.putFloat(key, value).apply();
}
- private static void saveLongPreference(Context context, String key, long value) {
- SharedPreferences.Editor appPreferences = getDefaultSharedPreferences(context.getApplicationContext()).edit();
- appPreferences.putLong(key, value);
- appPreferences.apply();
- }
-
public static SharedPreferences getDefaultSharedPreferences(Context context) {
return android.preference.PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
}
diff --git a/src/main/java/com/owncloud/android/db/ProviderMeta.java b/src/main/java/com/owncloud/android/db/ProviderMeta.java
index 764be0943aab..ce4bd5c0f678 100644
--- a/src/main/java/com/owncloud/android/db/ProviderMeta.java
+++ b/src/main/java/com/owncloud/android/db/ProviderMeta.java
@@ -32,7 +32,7 @@
public class ProviderMeta {
public static final String DB_NAME = "filelist";
- public static final int DB_VERSION = 22;
+ public static final int DB_VERSION = 23;
private ProviderMeta() {
}
@@ -46,6 +46,7 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String EXTERNAL_LINKS_TABLE_NAME = "external_links";
public static final String ARBITRARY_DATA_TABLE_NAME = "arbitrary_data";
public static final String VIRTUAL_TABLE_NAME = "virtual";
+ public static final String FILESYSTEM_TABLE_NAME = "filesystem";
private static final String CONTENT_PREFIX = "content://";
@@ -68,6 +69,9 @@ static public class ProviderTableMeta implements BaseColumns {
public static final Uri CONTENT_URI_ARBITRARY_DATA = Uri.parse(CONTENT_PREFIX
+ MainApp.getAuthority() + "/arbitrary_data");
public static final Uri CONTENT_URI_VIRTUAL = Uri.parse(CONTENT_PREFIX + MainApp.getAuthority() + "/virtual");
+ public static final Uri CONTENT_URI_FILESYSTEM = Uri.parse(CONTENT_PREFIX
+ + MainApp.getAuthority() + "/filesystem");
+
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";
public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file";
@@ -169,6 +173,8 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String UPLOADS_LAST_RESULT = "last_result";
public static final String UPLOADS_CREATED_BY = "created_by";
public static final String UPLOADS_DEFAULT_SORT_ORDER = ProviderTableMeta._ID + " collate nocase desc";
+ public static final String UPLOADS_IS_WHILE_CHARGING_ONLY = "is_while_charging_only";
+ public static final String UPLOADS_IS_WIFI_ONLY = "is_wifi_only";
// Columns of synced folder table
public static final String SYNCED_FOLDER_LOCAL_PATH = "local_path";
@@ -176,6 +182,7 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String SYNCED_FOLDER_WIFI_ONLY = "wifi_only";
public static final String SYNCED_FOLDER_CHARGING_ONLY = "charging_only";
public static final String SYNCED_FOLDER_ENABLED = "enabled";
+ public static final String SYNCED_FOLDER_TYPE = "type";
public static final String SYNCED_FOLDER_SUBFOLDER_BY_DATE = "subfolder_by_date";
public static final String SYNCED_FOLDER_ACCOUNT = "account";
public static final String SYNCED_FOLDER_UPLOAD_ACTION = "upload_option";
@@ -192,8 +199,17 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String ARBITRARY_DATA_KEY = "key";
public static final String ARBITRARY_DATA_VALUE = "value";
+
// Columns of virtual
public static final String VIRTUAL_TYPE = "type";
public static final String VIRTUAL_OCFILE_ID = "ocfile_id";
+
+ // Columns of filesystem data table
+ public static final String FILESYSTEM_FILE_LOCAL_PATH = "local_path";
+ public static final String FILESYSTEM_FILE_MODIFIED = "modified_at";
+ public static final String FILESYSTEM_FILE_IS_FOLDER = "is_folder";
+ public static final String FILESYSTEM_FILE_FOUND_RECENTLY = "found_at";
+ public static final String FILESYSTEM_FILE_SENT_FOR_UPLOAD = "upload_triggered";
+ public static final String FILESYSTEM_SYNCED_FOLDER_ID = "syncedfolder_id";
}
}
\ No newline at end of file
diff --git a/src/main/java/com/owncloud/android/db/UploadResult.java b/src/main/java/com/owncloud/android/db/UploadResult.java
index eee69fbc3c63..41112108fcb4 100644
--- a/src/main/java/com/owncloud/android/db/UploadResult.java
+++ b/src/main/java/com/owncloud/android/db/UploadResult.java
@@ -35,7 +35,8 @@ public enum UploadResult {
DELAYED_FOR_WIFI(9),
SERVICE_INTERRUPTED(10),
DELAYED_FOR_CHARGING(11),
- MAINTENANCE_MODE(12);
+ MAINTENANCE_MODE(12),
+ LOCK_FAILED(13);
private final int value;
@@ -77,6 +78,8 @@ public static UploadResult fromValue(int value) {
return DELAYED_FOR_CHARGING;
case 12:
return MAINTENANCE_MODE;
+ case 13:
+ return LOCK_FAILED;
}
return null;
}
@@ -120,6 +123,8 @@ public static UploadResult fromOperationResult(RemoteOperationResult result) {
return UNKNOWN;
case MAINTENANCE_MODE:
return MAINTENANCE_MODE;
+ case LOCK_FAILED:
+ return LOCK_FAILED;
default:
return UNKNOWN;
}
diff --git a/src/main/java/com/owncloud/android/files/InstantUploadBroadcastReceiver.java b/src/main/java/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
deleted file mode 100644
index c5a21b55c991..000000000000
--- a/src/main/java/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/**
- * ownCloud Android client application
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2016 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.files;
-
-import android.Manifest;
-import android.accounts.Account;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.Build;
-import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Video;
-import android.support.v4.content.ContextCompat;
-
-import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountUtils;
-import com.owncloud.android.db.PreferenceManager;
-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;
-
-
-public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
-
- private static final String TAG = InstantUploadBroadcastReceiver.class.getName();
- // Image action
- // Unofficial action, works for most devices but not HTC. See: https://github.com/owncloud/android/issues/6
- private static final String NEW_PHOTO_ACTION_UNOFFICIAL = "com.android.camera.NEW_PICTURE";
- // Officially supported action since SDK 14:
- // http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_PICTURE
- private static final String NEW_PHOTO_ACTION = "android.hardware.action.NEW_PICTURE";
- // Video action
- // Officially supported action since SDK 14:
- // http://developer.android.com/reference/android/hardware/Camera.html#ACTION_NEW_VIDEO
- private static final String NEW_VIDEO_ACTION = "android.hardware.action.NEW_VIDEO";
-
- /**
- * Because we support NEW_PHOTO_ACTION and NEW_PHOTO_ACTION_UNOFFICIAL it can happen that
- * handleNewPictureAction is called twice for the same photo. Use this simple static variable to
- * remember last uploaded photo to filter duplicates. Must not be null!
- */
- static String lastUploadedPhotoPath = "";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- 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);
- Log_OC.d(TAG, "UNOFFICIAL processed: com.android.camera.NEW_PICTURE");
- } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
- handleNewPictureAction(context, intent);
- Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_PICTURE");
- } else if (intent.getAction().equals(NEW_VIDEO_ACTION)) {
- handleNewVideoAction(context, intent);
- Log_OC.d(TAG, "OFFICIAL processed: android.hardware.action.NEW_VIDEO");
- } else {
- Log_OC.e(TAG, "Incorrect intent received: " + intent.getAction());
- }
- }
- }
-
- private void handleNewPictureAction(Context context, Intent intent) {
- Cursor c = null;
- String file_path = null;
- String file_name = null;
- String mime_type = null;
- long date_taken = 0;
-
- Log_OC.i(TAG, "New photo received");
-
- if (!PreferenceManager.instantPictureUploadEnabled(context)) {
- Log_OC.d(TAG, "Instant picture upload disabled, ignoring new picture");
- return;
- }
-
- Account account = AccountUtils.getCurrentOwnCloudAccount(context);
- if (account == null) {
- Log_OC.w(TAG, "No account found for instant upload, aborting");
- return;
- }
-
- String[] CONTENT_PROJECTION = {
- Images.Media.DATA, Images.Media.DISPLAY_NAME, Images.Media.MIME_TYPE, Images.Media.SIZE};
-
- // if < Jelly Bean permission must be accepted during installation
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
- int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
-
- if (android.content.pm.PackageManager.PERMISSION_GRANTED != permissionCheck) {
- Log_OC.w(TAG, "Read external storage permission isn't granted, aborting");
- return;
- }
- }
-
- c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
- if (!c.moveToFirst()) {
- Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
- return;
- }
- file_path = c.getString(c.getColumnIndex(Images.Media.DATA));
- file_name = c.getString(c.getColumnIndex(Images.Media.DISPLAY_NAME));
- mime_type = c.getString(c.getColumnIndex(Images.Media.MIME_TYPE));
- date_taken = System.currentTimeMillis();
- c.close();
-
- if (file_path.equals(lastUploadedPhotoPath)) {
- Log_OC.d(TAG, "Duplicate detected: " + file_path + ". Ignore.");
- return;
- }
-
- lastUploadedPhotoPath = file_path;
- Log_OC.d(TAG, "Path: " + file_path + "");
-
- new FileUploader.UploadRequester();
-
- int behaviour = getUploadBehaviour(context);
- Boolean subfolderByDate = PreferenceManager.instantPictureUploadPathUseSubfolders(context);
- SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
- String uploadPathdef = context.getString(R.string.instant_upload_path);
- String uploadPath = pref.getString("instant_upload_path", uploadPathdef);
-
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.uploadNewFile(
- context,
- account,
- file_path,
- FileStorageUtils.getInstantUploadFilePath(uploadPath, file_name, date_taken, subfolderByDate),
- behaviour,
- mime_type,
- true, // create parent folder if not existent
- UploadFileOperation.CREATED_AS_INSTANT_PICTURE
- );
- }
-
- private Integer getUploadBehaviour(Context context) {
- SharedPreferences appPreferences = android.preference.PreferenceManager.getDefaultSharedPreferences(context);
- String behaviour = appPreferences.getString("prefs_instant_behaviour", "NOTHING");
-
- if (behaviour.equalsIgnoreCase("NOTHING")) {
- Log_OC.d(TAG, "upload file and do nothing");
- return FileUploader.LOCAL_BEHAVIOUR_FORGET;
- } else if (behaviour.equalsIgnoreCase("MOVE")) {
- Log_OC.d(TAG, "upload file and move file to oc folder");
- return FileUploader.LOCAL_BEHAVIOUR_MOVE;
- } else if (behaviour.equalsIgnoreCase("DELETE")) {
- Log_OC.d(TAG, "upload file and delete original file");
- return FileUploader.LOCAL_BEHAVIOUR_DELETE;
- }
- return FileUploader.LOCAL_BEHAVIOUR_FORGET;
- }
-
- private void handleNewVideoAction(Context context, Intent intent) {
- Cursor c = null;
- String file_path = null;
- String file_name = null;
- String mime_type = null;
- long date_taken = 0;
-
- Log_OC.i(TAG, "New video received");
-
- if (!PreferenceManager.instantVideoUploadEnabled(context)) {
- Log_OC.d(TAG, "Instant video upload disabled, ignoring new video");
- return;
- }
-
- Account account = AccountUtils.getCurrentOwnCloudAccount(context);
- if (account == null) {
- Log_OC.w(TAG, "No account found for instant upload, aborting");
- return;
- }
-
- String[] CONTENT_PROJECTION = {Video.Media.DATA, Video.Media.DISPLAY_NAME, Video.Media.MIME_TYPE,
- Video.Media.SIZE};
- c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
- if (!c.moveToFirst()) {
- Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
- return;
- }
- file_path = c.getString(c.getColumnIndex(Video.Media.DATA));
- file_name = c.getString(c.getColumnIndex(Video.Media.DISPLAY_NAME));
- mime_type = c.getString(c.getColumnIndex(Video.Media.MIME_TYPE));
- c.close();
- date_taken = System.currentTimeMillis();
- Log_OC.d(TAG, file_path + "");
-
- int behaviour = getUploadBehaviour(context);
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.uploadNewFile(
- context,
- account,
- file_path,
- FileStorageUtils.getInstantVideoUploadFilePath(context, file_name, date_taken),
- behaviour,
- mime_type,
- true, // create parent folder if not existent
- UploadFileOperation.CREATED_AS_INSTANT_VIDEO
- );
- }
-
-}
diff --git a/src/main/java/com/owncloud/android/files/services/ConnectivityActionReceiver.java b/src/main/java/com/owncloud/android/files/services/ConnectivityActionReceiver.java
deleted file mode 100755
index f6c34399f00f..000000000000
--- a/src/main/java/com/owncloud/android/files/services/ConnectivityActionReceiver.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/**
- * ownCloud Android client application
- *
- * @author LukeOwncloud
- * Copyright (C) 2016 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.files.services;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-
-import com.owncloud.android.db.PreferenceManager;
-import com.owncloud.android.db.UploadResult;
-import com.owncloud.android.lib.common.utils.Log_OC;
-
-/**
- * Receives all connectivity action from Android OS at all times and performs
- * required OC actions. For now that are: - Signal connectivity to
- * {@link FileUploader}.
- *
- * Later can be added: - Signal connectivity to download service, deletion
- * service, ... - Handle offline mode (cf.
- * https://github.com/owncloud/android/issues/162)
- *
- * Have fun with the comments :S
- */
-public class ConnectivityActionReceiver extends BroadcastReceiver {
- private static final String TAG = ConnectivityActionReceiver.class.getSimpleName();
-
- /**
- * Magic keyword, by Google.
- *
- * {@see http://developer.android.com/intl/es/reference/android/net/wifi/WifiInfo.html#getSSID()}
- */
- private static final String UNKNOWN_SSID = "";
-
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- // LOG ALL EVENTS:
- Log_OC.v(TAG, "action: " + intent.getAction());
- Log_OC.v(TAG, "component: " + intent.getComponent());
- Bundle extras = intent.getExtras();
- if (extras != null) {
- for (String key : extras.keySet()) {
- Log_OC.v(TAG, "key [" + key + "]: " + extras.get(key));
- }
- } else {
- Log_OC.v(TAG, "no extras");
- }
-
- if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED) &&
- (PreferenceManager.instantPictureUploadEnabled(context) &&
- PreferenceManager.instantPictureUploadWhenChargingOnly(context)) ||
- (PreferenceManager.instantVideoUploadEnabled(context) &&
- PreferenceManager.instantVideoUploadWhenChargingOnly(context))
- ) {
- // for the moment, only recovery of instant uploads, similar to behaviour in release 1.9.1
- Log_OC.d(TAG, "Requesting retry of instant uploads (& friends) due to charging");
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.retryFailedUploads(
- context,
- null,
- UploadResult.DELAYED_FOR_CHARGING // for the rest of enqueued when Wifi fell
- );
- }
-
- /**
- * There is an interesting mess to process WifiManager.NETWORK_STATE_CHANGED_ACTION and
- * ConnectivityManager.CONNECTIVITY_ACTION in a simple and reliable way.
- *
- * The former triggers much more events than what we really need to know about Wifi connection.
- *
- * But there are annoying uncertainties about ConnectivityManager.CONNECTIVITY_ACTION due
- * to the deprecation of ConnectivityManager.EXTRA_NETWORK_INFO in API level 14, and the absence
- * of ConnectivityManager.EXTRA_NETWORK_TYPE until API level 17. Dear Google, how should we
- * handle API levels 14 to 16?
- *
- * In the end maybe we need to keep in memory the current knowledge about connectivity
- * and update it taking into account several Intents received in a row
- *
- * But first let's try something "simple" to keep a basic retry of instant uploads in
- * version 1.9.2, similar to the existent until 1.9.1. To be improved.
- */
- if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- NetworkInfo networkInfo =
- intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
- WifiInfo wifiInfo =
- intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
- String bssid =
- intent.getStringExtra(WifiManager.EXTRA_BSSID);
- if(networkInfo.isConnected() && // not enough; see (*) right below
- wifiInfo != null &&
- !UNKNOWN_SSID.equals(wifiInfo.getSSID().toLowerCase()) &&
- bssid != null
- ) {
- Log_OC.d(TAG, "WiFi connected");
-
- wifiConnected(context);
- } else {
- // TODO tons of things to check to conclude disconnection;
- // TODO maybe alternative commented below, based on CONNECTIVITY_ACTION is better
- Log_OC.d(TAG, "WiFi disconnected ... but don't know if right now");
- }
- }
- // (*) When WiFi is lost, an Intent with network state CONNECTED and SSID "" is
- // received right before another Intent with network state DISCONNECTED; needs to
- // be differentiated of a new Wifi connection.
- //
- // Besides, with a new connection two Intents are received, having only the second the extra
- // WifiManager.EXTRA_BSSID, with the BSSID of the access point accessed.
- //
- // Not sure if this protocol is exact, since it's not documented. Only found mild references in
- // - http://developer.android.com/intl/es/reference/android/net/wifi/WifiInfo.html#getSSID()
- // - http://developer.android.com/intl/es/reference/android/net/wifi/WifiManager.html#EXTRA_BSSID
- // and reproduced in Nexus 5 with Android 6.
-
-
- /**
- * Possible alternative attending ConnectivityManager.CONNECTIVITY_ACTION.
- *
- * Let's see what QA has to say
- *
- if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- NetworkInfo networkInfo = intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO // deprecated in API 14
- );
- int networkType = intent.getIntExtra(
- ConnectivityManager.EXTRA_NETWORK_TYPE, // only from API level 17
- -1
- );
- boolean couldBeWifiAction =
- (networkInfo == null && networkType < 0) || // cases of lack of info
- networkInfo.getType() == ConnectivityManager.TYPE_WIFI ||
- networkType == ConnectivityManager.TYPE_WIFI;
-
- if (couldBeWifiAction) {
- if (ConnectivityUtils.isAppConnectedViaUnmeteredWiFi(context)) {
- Log_OC.d(TAG, "WiFi connected");
- wifiConnected(context);
- } else {
- Log_OC.d(TAG, "WiFi disconnected");
- wifiDisconnected(context);
- }
- } /* else, CONNECTIVIY_ACTION is (probably) about other network interface (mobile, bluetooth, ...)
- }
- */
- }
-
- private void wifiConnected(Context context) {
- // for the moment, only recovery of instant uploads, similar to behaviour in release 1.9.1
- if (
- (PreferenceManager.instantPictureUploadEnabled(context) &&
- PreferenceManager.instantPictureUploadViaWiFiOnly(context)) ||
- (PreferenceManager.instantVideoUploadEnabled(context) &&
- PreferenceManager.instantVideoUploadViaWiFiOnly(context))
- ) {
- Log_OC.d(TAG, "Requesting retry of instant uploads (& friends)");
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.retryFailedUploads(
- context,
- null,
- UploadResult.NETWORK_CONNECTION // for the interrupted when Wifi fell, if any
- // (side effect: any upload failed due to network error will be retried too, instant or not)
- );
- requester.retryFailedUploads(
- context,
- null,
- UploadResult.DELAYED_FOR_WIFI // for the rest of enqueued when Wifi fell
- );
- }
- }
-
- /**
- *
- private void wifiDisconnected() {
- // TODO something smart
-
- // NOTE: explicit cancellation of only-wifi instant uploads is not needed anymore, since currently:
- // - any upload in progress will be interrupted due to the lack of connectivity while the device
- // reconnects through other network interface;
- // - FileUploader checks instant upload settings and connection state before executing each
- // upload operation, so other pending instant uploads after the current one will not be run
- // (currently are silently moved to FAILED state)
- }
-
-
-
- static public void enableActionReceiver(Context context) {
- PackageManager pm = context.getPackageManager();
- ComponentName compName = new ComponentName(context.getApplicationContext(), ConnectivityActionReceiver.class);
- pm.setComponentEnabledSetting(compName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- }
-
- static public void disableActionReceiver(Context context) {
- PackageManager pm = context.getPackageManager();
- ComponentName compName = new ComponentName(context.getApplicationContext(), ConnectivityActionReceiver.class);
- pm.setComponentEnabledSetting(compName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- }
-
- */
-}
\ No newline at end of file
diff --git a/src/main/java/com/owncloud/android/files/services/FileUploader.java b/src/main/java/com/owncloud/android/files/services/FileUploader.java
index e98e71d2466f..7e1d4de507a9 100644
--- a/src/main/java/com/owncloud/android/files/services/FileUploader.java
+++ b/src/main/java/com/owncloud/android/files/services/FileUploader.java
@@ -34,7 +34,6 @@
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -45,6 +44,9 @@
import android.support.v4.app.NotificationCompat;
import android.util.Pair;
+import com.evernote.android.job.JobRequest;
+import com.evernote.android.job.util.Device;
+import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -77,6 +79,8 @@
import java.util.Map;
import java.util.Vector;
+import javax.annotation.Nullable;
+
/**
* Service for uploading files. Invoke using context.startService(...).
*
@@ -144,6 +148,9 @@ public class FileUploader extends Service
* Key to signal what is the origin of the upload request
*/
public static final String KEY_CREATED_BY = "CREATED_BY";
+
+ public static final String KEY_WHILE_ON_WIFI_ONLY = "KEY_ON_WIFI_ONLY";
+
/**
* Set to true if upload is to performed only when phone is being charged.
*/
@@ -194,7 +201,6 @@ public void onRenameUpload() {
sendBroadcastUploadStarted(mCurrentUpload);
}
-
/**
* Helper class providing methods to ease requesting commands to {@link FileUploader} .
*
@@ -214,7 +220,37 @@ public void uploadNewFile(
String[] mimeTypes,
Integer behaviour,
Boolean createRemoteFolder,
- int createdBy
+ int createdBy,
+ boolean requiresWifi,
+ boolean requiresCharging
+ ) {
+ Intent intent = new Intent(context, FileUploader.class);
+
+ intent.putExtra(FileUploader.KEY_ACCOUNT, account);
+ intent.putExtra(FileUploader.KEY_LOCAL_FILE, localPaths);
+ intent.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
+ intent.putExtra(FileUploader.KEY_MIME_TYPE, mimeTypes);
+ intent.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, behaviour);
+ intent.putExtra(FileUploader.KEY_CREATE_REMOTE_FOLDER, createRemoteFolder);
+ intent.putExtra(FileUploader.KEY_CREATED_BY, createdBy);
+ intent.putExtra(FileUploader.KEY_WHILE_ON_WIFI_ONLY, requiresWifi);
+ intent.putExtra(FileUploader.KEY_WHILE_CHARGING_ONLY, requiresCharging);
+
+ context.startService(intent);
+ }
+
+ public void uploadFileWithOverwrite(
+ Context context,
+ Account account,
+ String[] localPaths,
+ String[] remotePaths,
+ String[] mimeTypes,
+ Integer behaviour,
+ Boolean createRemoteFolder,
+ int createdBy,
+ boolean requiresWifi,
+ boolean requiresCharging,
+ boolean overwrite
) {
Intent intent = new Intent(context, FileUploader.class);
@@ -225,15 +261,41 @@ public void uploadNewFile(
intent.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, behaviour);
intent.putExtra(FileUploader.KEY_CREATE_REMOTE_FOLDER, createRemoteFolder);
intent.putExtra(FileUploader.KEY_CREATED_BY, createdBy);
+ intent.putExtra(FileUploader.KEY_WHILE_ON_WIFI_ONLY, requiresWifi);
+ intent.putExtra(FileUploader.KEY_WHILE_CHARGING_ONLY, requiresCharging);
+ intent.putExtra(FileUploader.KEY_FORCE_OVERWRITE, overwrite);
context.startService(intent);
}
+ /**
+ * Call to upload a file
+ */
+ public void uploadFileWithOverwrite(Context context, Account account, String localPath, String remotePath, int
+ behaviour, String mimeType, boolean createRemoteFile, int createdBy, boolean requiresWifi,
+ boolean requiresCharging, boolean overwrite) {
+
+ uploadFileWithOverwrite(
+ context,
+ account,
+ new String[]{localPath},
+ new String[]{remotePath},
+ new String[]{mimeType},
+ behaviour,
+ createRemoteFile,
+ createdBy,
+ requiresWifi,
+ requiresCharging,
+ overwrite
+ );
+ }
+
/**
* Call to upload a new single file
*/
public void uploadNewFile(Context context, Account account, String localPath, String remotePath, int
- behaviour, String mimeType, boolean createRemoteFile, int createdBy) {
+ behaviour, String mimeType, boolean createRemoteFile, int createdBy, boolean requiresWifi,
+ boolean requiresCharging) {
uploadNewFile(
context,
@@ -243,7 +305,9 @@ public void uploadNewFile(Context context, Account account, String localPath, St
new String[]{mimeType},
behaviour,
createRemoteFile,
- createdBy
+ createdBy,
+ requiresWifi,
+ requiresCharging
);
}
@@ -288,7 +352,6 @@ public void retry (Context context, OCUpload upload) {
}
}
-
/**
* Retry a subset of all the stored failed uploads.
*
@@ -306,7 +369,7 @@ public void retryFailedUploads(Context context, Account account, UploadResult up
boolean accountMatch;
for ( OCUpload failedUpload: failedUploads) {
accountMatch = (account == null || account.name.equals(failedUpload.getAccountName()));
- resultMatch = (uploadResult == null || uploadResult.equals(failedUpload.getLastResult()));
+ resultMatch = ((uploadResult == null || uploadResult.equals(failedUpload.getLastResult())));
if (accountMatch && resultMatch) {
if (currentAccount == null ||
!currentAccount.name.equals(failedUpload.getAccountName())) {
@@ -330,13 +393,12 @@ private void retry(Context context, Account account, OCUpload upload) {
i.putExtra(FileUploader.KEY_RETRY, true);
i.putExtra(FileUploader.KEY_ACCOUNT, account);
i.putExtra(FileUploader.KEY_RETRY_UPLOAD, upload);
+
context.startService(i);
}
}
-
}
-
/**
* Service initialization
*/
@@ -370,7 +432,6 @@ public void onCreate() {
am.addOnAccountsUpdatedListener(this, null, false);
}
-
/**
* Service clean-up when restarted after being killed
*/
@@ -379,7 +440,6 @@ private void resurrection() {
mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
}
-
/**
* Service clean up
*/
@@ -399,7 +459,6 @@ public void onDestroy() {
super.onDestroy();
}
-
/**
* Entry point to add one or several files to the queue of uploads.
*
@@ -426,9 +485,14 @@ public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
OwnCloudVersion ocv = AccountUtils.getServerVersion(account);
+
boolean chunked = ocv.isChunkedUploadSupported();
+ boolean onWifiOnly = intent.getBooleanExtra(KEY_WHILE_ON_WIFI_ONLY, false);
+ boolean whileChargingOnly = intent.getBooleanExtra(KEY_WHILE_CHARGING_ONLY, false);
+
if (!retry) {
+
if (!(intent.hasExtra(KEY_LOCAL_FILE) ||
intent.hasExtra(KEY_FILE))) {
Log_OC.e(TAG, "Not enough information provided in intent");
@@ -451,7 +515,6 @@ public int onStartCommand(Intent intent, int flags, int startId) {
mimeTypes = intent.getStringArrayExtra(KEY_MIME_TYPE);
}
-
boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_FORGET);
@@ -503,10 +566,12 @@ public int onStartCommand(Intent intent, int flags, int startId) {
ocUpload.setCreateRemoteFolder(isCreateRemoteFolder);
ocUpload.setCreatedBy(createdBy);
ocUpload.setLocalAction(localAction);
- /*ocUpload.setUseWifiOnly(isUseWifiOnly);
- ocUpload.setWhileChargingOnly(isWhileChargingOnly);*/
+ ocUpload.setUseWifiOnly(onWifiOnly);
+ ocUpload.setWhileChargingOnly(whileChargingOnly);
+
ocUpload.setUploadStatus(UploadStatus.UPLOAD_IN_PROGRESS);
+
newUpload = new UploadFileOperation(
account,
files[i],
@@ -514,7 +579,9 @@ public int onStartCommand(Intent intent, int flags, int startId) {
chunked,
forceOverwrite,
localAction,
- this
+ this,
+ onWifiOnly,
+ whileChargingOnly
);
newUpload.setCreatedBy(createdBy);
if (isCreateRemoteFolder) {
@@ -561,6 +628,9 @@ public int onStartCommand(Intent intent, int flags, int startId) {
}
OCUpload upload = intent.getParcelableExtra(KEY_RETRY_UPLOAD);
+ onWifiOnly = upload.isUseWifiOnly();
+ whileChargingOnly = upload.isWhileChargingOnly();
+
UploadFileOperation newUpload = new UploadFileOperation(
account,
null,
@@ -568,7 +638,9 @@ public int onStartCommand(Intent intent, int flags, int startId) {
chunked,
upload.isForceOverwrite(), // TODO should be read from DB?
upload.getLocalAction(), // TODO should be read from DB?
- this
+ this,
+ onWifiOnly,
+ whileChargingOnly
);
newUpload.addDatatransferProgressListener(this);
@@ -634,9 +706,8 @@ public void onAccountsUpdated(Account[] accounts) {
}
/**
- * Binder to let client components to perform operations on the queue of
- * uploads.
- *
+ * Binder to let client components to perform operations on the queue of uploads.
+ *
* It provides by itself the available operations.
*/
public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener {
@@ -645,9 +716,7 @@ public class FileUploaderBinder extends Binder implements OnDatatransferProgress
* Map of listeners that will be reported about progress of uploads from a
* {@link FileUploaderBinder} instance
*/
- private Map mBoundListeners =
- new HashMap();
-
+ private Map mBoundListeners = new HashMap<>();
/**
* Cancels a pending or current upload of a remote file.
@@ -656,7 +725,7 @@ public class FileUploaderBinder extends Binder implements OnDatatransferProgress
* @param file A file in the queue of pending uploads
*/
public void cancel(Account account, OCFile file) {
- cancel(account.name, file.getRemotePath());
+ cancel(account.name, file.getRemotePath(), null);
}
/**
@@ -665,7 +734,7 @@ public void cancel(Account account, OCFile file) {
* @param storedUpload Upload operation persisted
*/
public void cancel(OCUpload storedUpload) {
- cancel(storedUpload.getAccountName(), storedUpload.getRemotePath());
+ cancel(storedUpload.getAccountName(), storedUpload.getRemotePath(), null);
}
@@ -674,8 +743,10 @@ public void cancel(OCUpload storedUpload) {
*
* @param accountName Local name of an ownCloud account where the remote file will be stored.
* @param remotePath Remote target of the upload
+ *
+ * Setting result code will pause rather than cancel the job
*/
- private void cancel(String accountName, String remotePath) {
+ private void cancel(String accountName, String remotePath, @Nullable ResultCode resultCode ) {
Pair removeResult =
mPendingUploads.remove(accountName, remotePath);
UploadFileOperation upload = removeResult.first;
@@ -686,14 +757,17 @@ private void cancel(String accountName, String remotePath) {
upload = mCurrentUpload;
}
+
if (upload != null) {
upload.cancel();
// need to update now table in mUploadsStorageManager,
// since the operation will not get to be run by FileUploader#uploadFile
- mUploadsStorageManager.removeUpload(accountName, remotePath);
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- // try to cancel job in jobScheduler
- mUploadsStorageManager.cancelPendingJob(accountName, remotePath);
+ if (resultCode != null) {
+ mUploadsStorageManager.updateDatabaseUploadResult(new RemoteOperationResult(resultCode), upload);
+ notifyUploadResult(upload, new RemoteOperationResult(resultCode));
+ } else {
+ mUploadsStorageManager.removeUpload(accountName, remotePath);
+ }
}
}
@@ -740,7 +814,6 @@ public boolean isUploading(Account account, OCFile file) {
return (mPendingUploads.contains(account.name, file.getRemotePath()));
}
-
public boolean isUploadingNow(OCUpload upload) {
return (
upload != null &&
@@ -751,7 +824,6 @@ public boolean isUploadingNow(OCUpload upload) {
);
}
-
/**
* Adds a listener interested in the progress of the upload for a concrete file.
*
@@ -771,7 +843,6 @@ public void addDatatransferProgressListener(
mBoundListeners.put(targetKey, listener);
}
-
/**
* Adds a listener interested in the progress of the upload for a concrete file.
*
@@ -789,7 +860,6 @@ public void addDatatransferProgressListener(
mBoundListeners.put(targetKey, listener);
}
-
/**
* Removes a listener interested in the progress of the upload for a concrete file.
*
@@ -811,7 +881,6 @@ public void removeDatatransferProgressListener(
}
}
-
/**
* Removes a listener interested in the progress of the upload for a concrete file.
*
@@ -831,7 +900,6 @@ public void removeDatatransferProgressListener(
}
}
-
@Override
public void onTransferProgress(long progressRate, long totalTransferredSoFar,
long totalToTransfer, String fileName) {
@@ -840,12 +908,24 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar,
if (boundListener != null) {
boundListener.onTransferProgress(progressRate, totalTransferredSoFar,
totalToTransfer, fileName);
+
+ if (MainApp.getAppContext() != null) {
+ if (mCurrentUpload.getIsWifiRequired() && !Device.getNetworkType(MainApp.getAppContext()).
+ equals(JobRequest.NetworkType.UNMETERED)) {
+ cancel(mCurrentUpload.getAccount().name, mCurrentUpload.getFile().getRemotePath()
+ , ResultCode.DELAYED_FOR_WIFI);
+ } else if (mCurrentUpload.getIsChargingRequired() &&
+ !Device.isCharging(MainApp.getAppContext())) {
+ cancel(mCurrentUpload.getAccount().name, mCurrentUpload.getFile().getRemotePath()
+ , ResultCode.DELAYED_FOR_CHARGING);
+ }
+ }
}
}
/**
* Builds a key for the map of listeners.
- *
+ *
* TODO use method in IndexedForest, or refactor both to a common place
* add to local database) to better policy (add to local database, then upload)
*
@@ -863,7 +943,7 @@ private String buildRemoteName(String accountName, String remotePath) {
/**
* Upload worker. Performs the pending uploads in the order they were
* requested.
- *
+ *
* Created with the Looper of a new thread, started in
* {@link FileUploader#onCreate()}.
*/
@@ -958,7 +1038,7 @@ public void uploadFile(String uploadKey) {
mCurrentAccount.name,
mCurrentUpload.getOldFile().getRemotePath()
);
- /** TODO: grant that name is also updated for mCurrentUpload.getOCUploadId */
+ // TODO: grant that name is also updated for mCurrentUpload.getOCUploadId
} else {
removeResult = mPendingUploads.removePayload(
@@ -973,7 +1053,6 @@ public void uploadFile(String uploadKey) {
notifyUploadResult(mCurrentUpload, uploadResult);
sendBroadcastUploadFinished(mCurrentUpload, uploadResult, removeResult.second);
-
}
// generate new Thumbnail
@@ -997,8 +1076,7 @@ public void uploadFile(String uploadKey) {
private void notifyUploadStart(UploadFileOperation upload) {
// / create status notification with a progress bar
mLastPercent = 0;
- mNotificationBuilder =
- NotificationUtils.newNotificationBuilder(this);
+ mNotificationBuilder = NotificationUtils.newNotificationBuilder(this);
mNotificationBuilder
.setOngoing(true)
.setSmallIcon(R.drawable.notification_icon)
@@ -1022,7 +1100,6 @@ private void notifyUploadStart(UploadFileOperation upload) {
} // else wait until the upload really start (onTransferProgress is called), so that if it's discarded
// due to lack of Wifi, no notification is shown
// TODO generalize for automated uploads
-
}
/**
@@ -1058,7 +1135,8 @@ private void notifyUploadResult(UploadFileOperation upload,
if (!uploadResult.isCancelled() &&
!ResultCode.LOCAL_FILE_NOT_FOUND.equals(uploadResult.getCode()) &&
!uploadResult.getCode().equals(ResultCode.DELAYED_FOR_WIFI) &&
- !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_CHARGING)) {
+ !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_CHARGING) &&
+ !uploadResult.getCode().equals(ResultCode.LOCK_FAILED) ) {
int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker :
R.string.uploader_upload_failed_ticker;
@@ -1077,9 +1155,7 @@ private void notifyUploadResult(UploadFileOperation upload,
.setOngoing(false)
.setProgress(0, 0, false);
- content = ErrorMessageAdapter.getErrorCauseMessage(
- uploadResult, upload, getResources()
- );
+ content = ErrorMessageAdapter.getErrorCauseMessage(uploadResult, upload, getResources());
if (needsToUpdateCredentials) {
// let the user update credentials with one click
@@ -1130,7 +1206,6 @@ uploadResult, upload, getResources()
}
}
-
/**
* Sends a broadcast in order to the interested activities can update their
* view
@@ -1144,7 +1219,6 @@ private void sendBroadcastUploadsAdded() {
sendStickyBroadcast(start);
}
-
/**
* Sends a broadcast in order to the interested activities can update their
* view
@@ -1208,5 +1282,4 @@ private void cancelUploadsForAccount(Account account) {
mPendingUploads.remove(account.name);
mUploadsStorageManager.removeUploads(account.name);
}
-
}
diff --git a/src/main/java/com/owncloud/android/services/AccountRemovalJob.java b/src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java
similarity index 96%
rename from src/main/java/com/owncloud/android/services/AccountRemovalJob.java
rename to src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java
index 0414f6b59043..97024961f500 100644
--- a/src/main/java/com/owncloud/android/services/AccountRemovalJob.java
+++ b/src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-package com.owncloud.android.services;
+package com.owncloud.android.jobs;
import android.accounts.Account;
import android.accounts.AccountManager;
@@ -76,7 +76,7 @@ protected Result onRunJob(Params params) {
// remove pending account removal
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
- arbitraryDataProvider.deleteKeyForAccount(account, PENDING_FOR_REMOVAL);
+ arbitraryDataProvider.deleteKeyForAccount(account.name, PENDING_FOR_REMOVAL);
return Result.SUCCESS;
} else {
diff --git a/src/main/java/com/owncloud/android/services/ContactsBackupJob.java b/src/main/java/com/owncloud/android/jobs/ContactsBackupJob.java
similarity index 97%
rename from src/main/java/com/owncloud/android/services/ContactsBackupJob.java
rename to src/main/java/com/owncloud/android/jobs/ContactsBackupJob.java
index a81140d0ee2f..15a30c85c464 100644
--- a/src/main/java/com/owncloud/android/services/ContactsBackupJob.java
+++ b/src/main/java/com/owncloud/android/jobs/ContactsBackupJob.java
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-package com.owncloud.android.services;
+package com.owncloud.android.jobs;
import android.accounts.Account;
import android.content.ComponentName;
@@ -44,6 +44,7 @@
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.services.OperationsService;
import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
import java.io.File;
@@ -97,7 +98,7 @@ protected Result onRunJob(Params params) {
OperationsService.BIND_AUTO_CREATE);
// store execution date
- arbitraryDataProvider.storeOrUpdateKeyValue(account,
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
ContactsPreferenceActivity.PREFERENCE_CONTACTS_LAST_BACKUP,
String.valueOf(Calendar.getInstance().getTimeInMillis()));
} else {
@@ -156,7 +157,9 @@ private void backupContact(Account account, String backupFolder) {
FileUploader.LOCAL_BEHAVIOUR_MOVE,
null,
true,
- UploadFileOperation.CREATED_BY_USER
+ UploadFileOperation.CREATED_BY_USER,
+ false,
+ false
);
} catch (Exception e) {
diff --git a/src/main/java/com/owncloud/android/services/ContactsImportJob.java b/src/main/java/com/owncloud/android/jobs/ContactsImportJob.java
similarity index 99%
rename from src/main/java/com/owncloud/android/services/ContactsImportJob.java
rename to src/main/java/com/owncloud/android/jobs/ContactsImportJob.java
index 3380d34d6290..247902711588 100644
--- a/src/main/java/com/owncloud/android/services/ContactsImportJob.java
+++ b/src/main/java/com/owncloud/android/jobs/ContactsImportJob.java
@@ -19,7 +19,7 @@
* along with this program. If not, see .
*/
-package com.owncloud.android.services;
+package com.owncloud.android.jobs;
import android.database.Cursor;
import android.net.Uri;
diff --git a/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java b/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java
new file mode 100644
index 000000000000..216cf3e7a8de
--- /dev/null
+++ b/src/main/java/com/owncloud/android/jobs/FilesSyncJob.java
@@ -0,0 +1,153 @@
+/**
+ * Nextcloud Android client application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic
+ * Copyright (C) 2017 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.jobs;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.PowerManager;
+import android.support.annotation.NonNull;
+import android.support.media.ExifInterface;
+import android.text.TextUtils;
+
+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.datamodel.FilesystemDataProvider;
+import com.owncloud.android.datamodel.MediaFolderType;
+import com.owncloud.android.datamodel.SyncedFolder;
+import com.owncloud.android.datamodel.SyncedFolderProvider;
+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.FilesSyncHelper;
+import com.owncloud.android.utils.MimeTypeUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/*
+ Job that:
+ - restarts existing jobs if required
+ - finds new and modified files since we last run this
+ - creates upload tasks
+ */
+public class FilesSyncJob extends Job {
+ public static final String TAG = "FilesSyncJob";
+
+ public static final String SKIP_CUSTOM = "skipCustom";
+
+ @NonNull
+ @Override
+ protected Result onRunJob(Params params) {
+ final Context context = MainApp.getAppContext();
+ final ContentResolver contentResolver = context.getContentResolver();
+
+ PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
+ PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ TAG);
+ wakeLock.acquire();
+
+ PersistableBundleCompat bundle = params.getExtras();
+ final boolean skipCustom = bundle.getBoolean(SKIP_CUSTOM, false);
+
+ FilesSyncHelper.restartJobsIfNeeded();
+ FilesSyncHelper.insertAllDBEntries(skipCustom);
+
+ // Create all the providers we'll need
+ final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
+ SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver);
+
+ for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
+ if ((syncedFolder.isEnabled()) && (!skipCustom || MediaFolderType.CUSTOM != syncedFolder.getType())) {
+ for (String path : filesystemDataProvider.getFilesForUpload(syncedFolder.getLocalPath(),
+ Long.toString(syncedFolder.getId()))) {
+ File file = new File(path);
+
+ Long lastModificationTime = file.lastModified();
+ final Locale currentLocale = context.getResources().getConfiguration().locale;
+
+ if (MediaFolderType.IMAGE == syncedFolder.getType()) {
+ String mimetypeString = FileStorageUtils.getMimeTypeFromName(file.getAbsolutePath());
+ 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());
+ }
+ }
+ }
+
+ boolean needsCharging = syncedFolder.getChargingOnly();
+ boolean needsWifi = syncedFolder.getWifiOnly();
+
+ String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(file.getAbsolutePath());
+
+ Account account = AccountUtils.getOwnCloudAccountByName(context, syncedFolder.getAccount());
+
+ requester.uploadFileWithOverwrite(
+ context,
+ account,
+ file.getAbsolutePath(),
+ FileStorageUtils.getInstantUploadFilePath(
+ currentLocale,
+ syncedFolder.getRemotePath(), file.getName(),
+ lastModificationTime,
+ syncedFolder.getSubfolderByDate()),
+ syncedFolder.getUploadAction(),
+ mimeType,
+ true, // create parent folder if not existent
+ UploadFileOperation.CREATED_AS_INSTANT_PICTURE,
+ needsWifi,
+ needsCharging,
+ true
+ );
+
+ filesystemDataProvider.updateFilesystemFileAsSentForUpload(path,
+ Long.toString(syncedFolder.getId()));
+ }
+ }
+ }
+
+ wakeLock.release();
+ return Result.SUCCESS;
+ }
+}
diff --git a/src/main/java/com/owncloud/android/services/NCJobCreator.java b/src/main/java/com/owncloud/android/jobs/NCJobCreator.java
similarity index 92%
rename from src/main/java/com/owncloud/android/services/NCJobCreator.java
rename to src/main/java/com/owncloud/android/jobs/NCJobCreator.java
index c3d2cd418256..2fdf85ca9265 100644
--- a/src/main/java/com/owncloud/android/services/NCJobCreator.java
+++ b/src/main/java/com/owncloud/android/jobs/NCJobCreator.java
@@ -18,7 +18,7 @@
* 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;
+package com.owncloud.android.jobs;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobCreator;
@@ -31,14 +31,14 @@ public class NCJobCreator implements JobCreator {
@Override
public Job create(String tag) {
switch (tag) {
- case AutoUploadJob.TAG:
- return new AutoUploadJob();
case ContactsBackupJob.TAG:
return new ContactsBackupJob();
case ContactsImportJob.TAG:
return new ContactsImportJob();
case AccountRemovalJob.TAG:
return new AccountRemovalJob();
+ case FilesSyncJob.TAG:
+ return new FilesSyncJob();
default:
return null;
}
diff --git a/src/main/java/com/owncloud/android/jobs/NContentObserverJob.java b/src/main/java/com/owncloud/android/jobs/NContentObserverJob.java
new file mode 100644
index 000000000000..7e5fc85417f1
--- /dev/null
+++ b/src/main/java/com/owncloud/android/jobs/NContentObserverJob.java
@@ -0,0 +1,69 @@
+/**
+ * Nextcloud Android client application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic
+ * Copyright (C) 2017 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.jobs;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+
+import com.evernote.android.job.JobRequest;
+import com.evernote.android.job.util.support.PersistableBundleCompat;
+import com.owncloud.android.utils.FilesSyncHelper;
+
+import java.util.concurrent.TimeUnit;
+
+/*
+ Job that triggers new FilesSyncJob in case new photo or video were detected
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+public class NContentObserverJob extends JobService {
+ @Override
+ public boolean onStartJob(JobParameters params) {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ if (params.getJobId() == FilesSyncHelper.ContentSyncJobId && params.getTriggeredContentAuthorities()
+ != null && params.getTriggeredContentUris() != null
+ && params.getTriggeredContentUris().length > 0) {
+
+ PersistableBundleCompat persistableBundleCompat = new PersistableBundleCompat();
+ persistableBundleCompat.putBoolean(FilesSyncJob.SKIP_CUSTOM, true);
+
+ new JobRequest.Builder(FilesSyncJob.TAG)
+ .setExecutionWindow(1, TimeUnit.SECONDS.toMillis(2))
+ .setBackoffCriteria(TimeUnit.SECONDS.toMillis(5), JobRequest.BackoffPolicy.LINEAR)
+ .setUpdateCurrent(false)
+ .build()
+ .schedule();
+ }
+
+ FilesSyncHelper.scheduleNJobs(true);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+}
diff --git a/src/main/java/com/owncloud/android/operations/MoveFileOperation.java b/src/main/java/com/owncloud/android/operations/MoveFileOperation.java
index 856d37f2ec2f..3ffb86b263d5 100644
--- a/src/main/java/com/owncloud/android/operations/MoveFileOperation.java
+++ b/src/main/java/com/owncloud/android/operations/MoveFileOperation.java
@@ -20,8 +20,6 @@
package com.owncloud.android.operations;
-import android.accounts.Account;
-
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@@ -41,17 +39,14 @@ public class MoveFileOperation extends SyncOperation {
private String mTargetParentPath;
private OCFile mFile;
-
-
/**
* Constructor
*
* @param srcPath Remote path of the {@link OCFile} to move.
* @param targetParentPath Path to the folder where the file will be moved into.
- * @param account OwnCloud account containing both the file and the target folder
*/
- public MoveFileOperation(String srcPath, String targetParentPath, Account account) {
+ public MoveFileOperation(String srcPath, String targetParentPath) {
mSrcPath = srcPath;
mTargetParentPath = targetParentPath;
if (!mTargetParentPath.endsWith(OCFile.PATH_SEPARATOR)) {
@@ -68,7 +63,7 @@ public MoveFileOperation(String srcPath, String targetParentPath, Account accoun
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
- RemoteOperationResult result = null;
+ RemoteOperationResult result;
/// 1. check move validity
if (mTargetParentPath.startsWith(mSrcPath)) {
diff --git a/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java
index 30918f158fdb..a3d57224efad 100644
--- a/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java
+++ b/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java
@@ -203,7 +203,7 @@ protected RemoteOperationResult run(OwnCloudClient client) {
if (result.isSuccess()) {
// request for the synchronization of KEPT-IN-SYNC file contents
- startContentSynchronizations(mFilesToSyncContents, client);
+ startContentSynchronizations(mFilesToSyncContents);
}
}
@@ -453,12 +453,9 @@ private void synchronizeData(ArrayList folderAndFiles) {
* on.
*
* @param filesToSyncContents Synchronization operations to execute.
- * @param client Interface to the remote ownCloud server.
*/
- private void startContentSynchronizations(
- List filesToSyncContents, OwnCloudClient client
- ) {
- RemoteOperationResult contentsResult = null;
+ private void startContentSynchronizations(List filesToSyncContents) {
+ RemoteOperationResult contentsResult;
for (SynchronizeFileOperation op: filesToSyncContents) {
contentsResult = op.execute(mStorageManager, mContext); // async
if (!contentsResult.isSuccess()) {
@@ -487,7 +484,7 @@ private void startContentSynchronizations(
* the operation.
*/
private RemoteOperationResult refreshSharesForFolder(OwnCloudClient client) {
- RemoteOperationResult result = null;
+ RemoteOperationResult result;
// remote request
GetRemoteSharesForFileOperation operation =
diff --git a/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java
index 4d1e939089d9..c63ae0c33bec 100644
--- a/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java
+++ b/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java
@@ -469,19 +469,6 @@ private void startContentSynchronizations(List filesToSyncContent
}
}
-
- /**
- * Creates and populates a new {@link com.owncloud.android.datamodel.OCFile}
- * object with the data read from the server.
- *
- * @param remote remote file read from the server (remote file or folder).
- * @return New OCFile instance representing the remote resource described by we.
- */
- private OCFile fillOCFile(RemoteFile remote) {
- return FileStorageUtils.fillOCFile(remote);
- }
-
-
/**
* Scans the default location for saving local copies of files searching for
* a 'lost' file with the same full name as the {@link com.owncloud.android.datamodel.OCFile}
diff --git a/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
index 10bc08a9fdd6..0e4d343aa496 100644
--- a/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
+++ b/src/main/java/com/owncloud/android/operations/UploadFileOperation.java
@@ -1,21 +1,20 @@
/**
- * ownCloud Android client application
+ * ownCloud Android client application
*
- * @author David A. Velasco
- * Copyright (C) 2016 ownCloud GmbH.
+ * @author David A. Velasco
+ * Copyright (C) 2016 ownCloud GmbH.
*
- * 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 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 .
+ * 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.operations;
@@ -24,11 +23,12 @@
import android.content.Context;
import android.net.Uri;
+import com.evernote.android.job.JobRequest;
+import com.evernote.android.job.util.Device;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.db.OCUpload;
-import com.owncloud.android.db.PreferenceManager;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
@@ -44,7 +44,6 @@
import com.owncloud.android.lib.resources.files.RemoteFile;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import com.owncloud.android.operations.common.SyncOperation;
-import com.owncloud.android.utils.ConnectivityUtils;
import com.owncloud.android.utils.FileStorageUtils;
import com.owncloud.android.utils.MimeType;
import com.owncloud.android.utils.MimeTypeUtil;
@@ -52,14 +51,20 @@
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.RequestEntity;
+import org.lukhnos.nnio.file.Files;
+import org.lukhnos.nnio.file.Paths;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -94,6 +99,8 @@ public class UploadFileOperation extends SyncOperation {
private boolean mForceOverwrite = false;
private int mLocalBehaviour = FileUploader.LOCAL_BEHAVIOUR_COPY;
private int mCreatedBy = CREATED_BY_USER;
+ private boolean mOnWifiOnly = false;
+ private boolean mWhileChargingOnly = false;
private boolean mWasRenamed = false;
private long mOCUploadId = -1;
@@ -147,7 +154,9 @@ public UploadFileOperation(Account account,
boolean chunked,
boolean forceOverwrite,
int localBehaviour,
- Context context
+ Context context,
+ boolean onWifiOnly,
+ boolean whileChargingOnly
) {
if (account == null) {
throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation " + "creation");
@@ -171,6 +180,8 @@ public UploadFileOperation(Account account,
} else {
mFile = file;
}
+ mOnWifiOnly = onWifiOnly;
+ mWhileChargingOnly = whileChargingOnly;
mRemotePath = upload.getRemotePath();
mChunked = chunked;
mForceOverwrite = forceOverwrite;
@@ -182,6 +193,14 @@ public UploadFileOperation(Account account,
mRemoteFolderToBeCreated = upload.isCreateRemoteFolder();
}
+ public boolean getIsWifiRequired() {
+ return mOnWifiOnly;
+ }
+
+ public boolean getIsChargingRequired() {
+ return mWhileChargingOnly;
+ }
+
public Account getAccount() {
return mAccount;
}
@@ -237,7 +256,7 @@ public void setCreatedBy(int createdBy) {
}
}
- public int getCreatedBy () {
+ public int getCreatedBy() {
return mCreatedBy;
}
@@ -249,9 +268,10 @@ public boolean isInstantVideo() {
return mCreatedBy == CREATED_AS_INSTANT_VIDEO;
}
- public void setOCUploadId(long id){
+ public void setOCUploadId(long id) {
mOCUploadId = id;
}
+
public long getOCUploadId() {
return mOCUploadId;
}
@@ -260,14 +280,14 @@ public Set getDataTransferListeners() {
return mDataTransferListeners;
}
- public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
+ public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.add(listener);
}
if (mEntity != null) {
- ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener);
+ ((ProgressiveDataTransferer) mEntity).addDatatransferProgressListener(listener);
}
- if(mUploadOperation != null){
+ if (mUploadOperation != null) {
mUploadOperation.addDatatransferProgressListener(listener);
}
}
@@ -277,14 +297,14 @@ public void removeDatatransferProgressListener(OnDatatransferProgressListener li
mDataTransferListeners.remove(listener);
}
if (mEntity != null) {
- ((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener);
+ ((ProgressiveDataTransferer) mEntity).removeDatatransferProgressListener(listener);
}
- if(mUploadOperation != null){
+ if (mUploadOperation != null) {
mUploadOperation.removeDatatransferProgressListener(listener);
}
}
- public void addRenameUploadListener (OnRenameListener listener) {
+ public void addRenameUploadListener(OnRenameListener listener) {
mRenameUploadListener = listener;
}
@@ -297,17 +317,18 @@ protected RemoteOperationResult run(OwnCloudClient client) {
File temporalFile = null;
File originalFile = new File(mOriginalStoragePath);
File expectedFile = null;
+ FileLock fileLock = null;
try {
/// Check that connectivity conditions are met and delays the upload otherwise
- if (delayForWifi()) {
+ if (mOnWifiOnly && !Device.getNetworkType(mContext).equals(JobRequest.NetworkType.UNMETERED)) {
Log_OC.d(TAG, "Upload delayed until WiFi is available: " + getRemotePath());
return new RemoteOperationResult(ResultCode.DELAYED_FOR_WIFI);
}
// Check if charging conditions are met and delays the upload otherwise
- if (delayForCharging()){
+ if (mWhileChargingOnly && !Device.isCharging(mContext)) {
Log_OC.d(TAG, "Upload delayed until the device is charging: " + getRemotePath());
return new RemoteOperationResult(ResultCode.DELAYED_FOR_CHARGING);
}
@@ -372,20 +393,21 @@ protected RemoteOperationResult run(OwnCloudClient client) {
}
// Get the last modification date of the file from the file system
- Long timeStampLong = originalFile.lastModified()/1000;
+ Long timeStampLong = originalFile.lastModified() / 1000;
String timeStamp = timeStampLong.toString();
/// perform the upload
- if ( mChunked &&
+ if (mChunked &&
(new File(mFile.getStoragePath())).length() >
- ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
+ ChunkedUploadRemoteFileOperation.CHUNK_SIZE) {
mUploadOperation = new ChunkedUploadRemoteFileOperation(mContext, mFile.getStoragePath(),
mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp);
} else {
mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(),
mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp);
}
- Iterator listener = mDataTransferListeners.iterator();
+
+ Iterator listener = mDataTransferListeners.iterator();
while (listener.hasNext()) {
mUploadOperation.addDatatransferProgressListener(listener.next());
}
@@ -394,23 +416,77 @@ protected RemoteOperationResult run(OwnCloudClient client) {
throw new OperationCancelledException();
}
+ FileChannel channel = null;
+ try {
+ channel = new RandomAccessFile(mFile.getStoragePath(), "rw").getChannel();
+ fileLock = channel.tryLock();
+ } catch (FileNotFoundException e) {
+ if (temporalFile == null) {
+ String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
+ mFile.setStoragePath(temporalPath);
+ temporalFile = new File(temporalPath);
+
+ result = copy(originalFile, temporalFile);
+
+ if (result != null) {
+ return result;
+ } else {
+ if (temporalFile.length() == originalFile.length()) {
+ channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
+ fileLock = channel.tryLock();
+ } else {
+ while (temporalFile.length() != originalFile.length()) {
+ Files.deleteIfExists(Paths.get(temporalPath));
+ result = copy(originalFile, temporalFile);
+
+ if (result != null) {
+ return result;
+ } else {
+ channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").
+ getChannel();
+ fileLock = channel.tryLock();
+ }
+ }
+ }
+ }
+ } else {
+ channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
+ fileLock = channel.tryLock();
+ }
+ }
+
result = mUploadOperation.execute(client);
/// move local temporal file or original file to its corresponding
// location in the ownCloud local folder
- if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED ) {
+ if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) {
result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
}
+ } catch (FileNotFoundException e) {
+ Log_OC.d(TAG, mOriginalStoragePath + " not exists anymore");
+ result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
+ } catch (OverlappingFileLockException e) {
+ Log_OC.d(TAG, "Overlapping file lock exception");
+ result = new RemoteOperationResult(ResultCode.LOCK_FAILED);
} catch (Exception e) {
result = new RemoteOperationResult(e);
} finally {
mUploadStarted.set(false);
+
+ if (fileLock != null) {
+ try {
+ fileLock.release();
+ } catch (IOException e) {
+ Log_OC.e(TAG, "Failed to unlock file with path " + mOriginalStoragePath);
+ }
+ }
+
if (temporalFile != null && !originalFile.equals(temporalFile)) {
temporalFile.delete();
}
- if (result == null){
+ if (result == null) {
result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
}
if (result.isSuccess()) {
@@ -418,7 +494,7 @@ protected RemoteOperationResult run(OwnCloudClient client) {
result.getLogMessage());
} else {
if (result.getException() != null) {
- if(result.isCancelled()){
+ if (result.isCancelled()) {
Log_OC.w(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
": " + result.getLogMessage());
} else {
@@ -478,41 +554,6 @@ protected RemoteOperationResult run(OwnCloudClient client) {
return result;
}
-
- /**
- * Checks origin of current upload and network type to decide if should be delayed, according to
- * current user preferences.
- *
- * @return 'True' if the upload was delayed until WiFi connectivity is available, 'false' otherwise.
- */
- private boolean delayForWifi() {
- boolean delayInstantPicture = (
- isInstantPicture() && PreferenceManager.instantPictureUploadViaWiFiOnly(mContext)
- );
- boolean delayInstantVideo = (
- isInstantVideo() && PreferenceManager.instantVideoUploadViaWiFiOnly(mContext)
- );
- return (
- (delayInstantPicture || delayInstantVideo) &&
- !ConnectivityUtils.isAppConnectedViaUnmeteredWiFi(mContext)
- );
- }
-
- /**
- * Check if upload should be delayed due to not charging
- *
- * @return 'True' if the upload was delayed until device is charging, 'false' otherwise.
- */
- private boolean delayForCharging() {
- boolean delayInstantPicture = isInstantPicture() &&
- PreferenceManager.instantPictureUploadWhenChargingOnly(mContext);
-
- boolean delayInstantVideo = isInstantVideo() && PreferenceManager.instantVideoUploadWhenChargingOnly(mContext);
-
- return ((delayInstantPicture || delayInstantVideo) && !ConnectivityUtils.isCharging(mContext));
- }
-
-
/**
* Checks the existence of the folder where the current file will be uploaded both
* in the remote server and in the local database.
@@ -566,7 +607,8 @@ private OCFile createLocalFolder(String remotePath) {
/**
* Create a new OCFile mFile with new remote path. This is required if forceOverwrite==false.
- * New file is stored as mFile, original as mOldFile.
+ * New file is stored as mFile, original as mOldFile.
+ *
* @param newRemotePath new remote path
*/
private void createNewOCFile(String newRemotePath) {
@@ -615,8 +657,7 @@ private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) {
suffix = " (" + count + ")";
if (pos >= 0) {
check = existsFile(wc, remotePath + suffix + "." + extension);
- }
- else {
+ } else {
check = existsFile(wc, remotePath + suffix);
}
count++;
@@ -629,7 +670,7 @@ private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) {
}
}
- private boolean existsFile(OwnCloudClient client, String remotePath){
+ private boolean existsFile(OwnCloudClient client, String remotePath) {
ExistenceCheckRemoteOperation existsOperation =
new ExistenceCheckRemoteOperation(remotePath, mContext, false);
RemoteOperationResult result = existsOperation.execute(client);
@@ -667,10 +708,10 @@ public boolean isUploadInProgress() {
* TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
* TODO use Exceptions instead
*
- * @param sourceFile Source file to copy.
- * @param targetFile Target location to copy the file.
- * @return {@link RemoteOperationResult}
- * @throws IOException
+ * @param sourceFile Source file to copy.
+ * @param targetFile Target location to copy the file.
+ * @return {@link RemoteOperationResult}
+ * @throws IOException
*/
private RemoteOperationResult copy(File sourceFile, File targetFile) throws IOException {
Log_OC.d(TAG, "Copying local file");
@@ -758,10 +799,10 @@ private RemoteOperationResult copy(File sourceFile, File targetFile) throws IOEx
*
* TODO refactor both this and 'copy' in a single method
*
- * @param sourceFile Source file to move.
- * @param targetFile Target location to move the file.
- * @return {@link RemoteOperationResult}
- * @throws IOException
+ * @param sourceFile Source file to move.
+ * @param targetFile Target location to move the file.
+ * @return {@link RemoteOperationResult}
+ * @throws IOException
*/
private void move(File sourceFile, File targetFile) throws IOException {
@@ -769,8 +810,8 @@ private void move(File sourceFile, File targetFile) throws IOException {
File expectedFolder = targetFile.getParentFile();
expectedFolder.mkdirs();
- if (expectedFolder.isDirectory()){
- if (!sourceFile.renameTo(targetFile)){
+ if (expectedFolder.isDirectory()) {
+ if (!sourceFile.renameTo(targetFile)) {
// try to copy and then delete
targetFile.createNewFile();
FileChannel inChannel = new FileInputStream(sourceFile).getChannel();
@@ -778,12 +819,11 @@ private void move(File sourceFile, File targetFile) throws IOException {
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
sourceFile.delete();
- } catch (Exception e){
+ } catch (Exception e) {
mFile.setStoragePath(""); // forget the local file
// by now, treat this as a success; the file was uploaded
// the best option could be show a warning message
- }
- finally {
+ } finally {
if (inChannel != null) {
inChannel.close();
}
@@ -847,7 +887,7 @@ private void saveUploadedFile(OwnCloudClient client) {
// generate new Thumbnail
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
- new ThumbnailsCacheManager.ThumbnailGenerationTask(getStorageManager(), mAccount);
+ new ThumbnailsCacheManager.ThumbnailGenerationTask(getStorageManager(), mAccount);
task.execute(file);
}
diff --git a/src/main/java/org/nextcloud/providers/DocumentsStorageProvider.java b/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java
similarity index 99%
rename from src/main/java/org/nextcloud/providers/DocumentsStorageProvider.java
rename to src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java
index ca94302ec1e7..07dd5a93d93e 100644
--- a/src/main/java/org/nextcloud/providers/DocumentsStorageProvider.java
+++ b/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java
@@ -18,7 +18,7 @@
*
*/
-package org.nextcloud.providers;
+package com.owncloud.android.providers;
import android.accounts.Account;
import android.annotation.TargetApi;
diff --git a/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/src/main/java/com/owncloud/android/providers/FileContentProvider.java
index 2a6b9d85e611..883649e00042 100644
--- a/src/main/java/com/owncloud/android/providers/FileContentProvider.java
+++ b/src/main/java/com/owncloud/android/providers/FileContentProvider.java
@@ -74,6 +74,7 @@ public class FileContentProvider extends ContentProvider {
private static final int EXTERNAL_LINKS = 8;
private static final int ARBITRARY_DATA = 9;
private static final int VIRTUAL = 10;
+ private static final int FILESYSTEM = 11;
private static final String TAG = FileContentProvider.class.getSimpleName();
@@ -209,6 +210,9 @@ private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs)
case VIRTUAL:
count = db.delete(ProviderTableMeta.VIRTUAL_TABLE_NAME, where, whereArgs);
break;
+ case FILESYSTEM:
+ count = db.delete(ProviderTableMeta.FILESYSTEM_TABLE_NAME, where, whereArgs);
+ break;
default:
//Log_OC.e(TAG, "Unknown uri " + uri);
throw new IllegalArgumentException("Unknown uri: " + uri.toString());
@@ -312,7 +316,6 @@ private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
if (uploadId > 0) {
insertedUploadUri =
ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_UPLOADS, uploadId);
- trimSuccessfulUploads(db);
} else {
throw new SQLException(ERROR + uri);
@@ -365,6 +368,16 @@ private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) {
}
return insertedVirtualUri;
+ case FILESYSTEM:
+ Uri insertedFilesystemUri = null;
+ long filesystedId = db.insert(ProviderTableMeta.FILESYSTEM_TABLE_NAME, null, values);
+ if (filesystedId > 0) {
+ insertedFilesystemUri =
+ ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILESYSTEM, filesystedId);
+ } else {
+ throw new SQLException("ERROR " + uri);
+ }
+ return insertedFilesystemUri;
default:
throw new IllegalArgumentException("Unknown uri id: " + uri);
}
@@ -417,6 +430,7 @@ public boolean onCreate() {
mUriMatcher.addURI(authority, "external_links", EXTERNAL_LINKS);
mUriMatcher.addURI(authority, "arbitrary_data", ARBITRARY_DATA);
mUriMatcher.addURI(authority, "virtual", VIRTUAL);
+ mUriMatcher.addURI(authority, "filesystem", FILESYSTEM);
return true;
}
@@ -518,6 +532,13 @@ private Cursor query(
sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1));
}
break;
+ case FILESYSTEM:
+ sqlQuery.setTables(ProviderTableMeta.FILESYSTEM_TABLE_NAME);
+ if (uri.getPathSegments().size() > 1) {
+ sqlQuery.appendWhere(ProviderTableMeta._ID + "="
+ + uri.getPathSegments().get(1));
+ }
+ break;
default:
throw new IllegalArgumentException("Unknown uri id: " + uri);
}
@@ -549,6 +570,9 @@ private Cursor query(
default: // Files
order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
break;
+ case FILESYSTEM:
+ order = ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH;
+ break;
}
} else {
order = sortOrder;
@@ -594,12 +618,13 @@ private int update(
return db.update(ProviderTableMeta.CAPABILITIES_TABLE_NAME, values, selection, selectionArgs);
case UPLOADS:
int ret = db.update(ProviderTableMeta.UPLOADS_TABLE_NAME, values, selection, selectionArgs);
- trimSuccessfulUploads(db);
return ret;
case SYNCED_FOLDERS:
return db.update(ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME, values, selection, selectionArgs);
case ARBITRARY_DATA:
return db.update(ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME, values, selection, selectionArgs);
+ case FILESYSTEM:
+ return db.update(ProviderTableMeta.FILESYSTEM_TABLE_NAME, values, selection, selectionArgs);
default:
return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs);
}
@@ -662,6 +687,9 @@ public void onCreate(SQLiteDatabase db) {
// Create virtual table
createVirtualTable(db);
+
+ // Create filesystem table
+ createFileSystemTable(db);
}
@Override
@@ -669,14 +697,14 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log_OC.i(SQL, "Entering in onUpgrade");
boolean upgraded = false;
if (oldVersion == 1 && newVersion >= 2) {
- Log_OC.i(SQL, "Entering in the #1 ADD in onUpgrade");
+ Log_OC.i(SQL, "Entering in the #2 ADD in onUpgrade");
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
ADD_COLUMN + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " +
" DEFAULT 0");
upgraded = true;
}
if (oldVersion < 3 && newVersion >= 3) {
- Log_OC.i(SQL, "Entering in the #2 ADD in onUpgrade");
+ Log_OC.i(SQL, "Entering in the #3 ADD in onUpgrade");
db.beginTransaction();
try {
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
@@ -696,7 +724,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
if (oldVersion < 4 && newVersion >= 4) {
- Log_OC.i(SQL, "Entering in the #3 ADD in onUpgrade");
+ Log_OC.i(SQL, "Entering in the #4 ADD in onUpgrade");
db.beginTransaction();
try {
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
@@ -720,7 +748,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
if (oldVersion < 5 && newVersion >= 5) {
- Log_OC.i(SQL, "Entering in the #4 ADD in onUpgrade");
+ Log_OC.i(SQL, "Entering in the #5 ADD in onUpgrade");
db.beginTransaction();
try {
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
@@ -738,7 +766,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
if (oldVersion < 6 && newVersion >= 6) {
- Log_OC.i(SQL, "Entering in the #5 ADD in onUpgrade");
+ Log_OC.i(SQL, "Entering in the #6 ADD in onUpgrade");
db.beginTransaction();
try {
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
@@ -843,6 +871,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.endTransaction();
}
}
+
if (!upgraded) {
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
}
@@ -937,7 +966,6 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
} finally {
db.endTransaction();
}
-
}
if (!upgraded) {
@@ -1033,6 +1061,43 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (!upgraded) {
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
}
+
+ if (oldVersion < 23 && newVersion >= 23) {
+ Log_OC.i(SQL, "Entering in the #23 adding type column for synced folders, Create filesystem table");
+ db.beginTransaction();
+ try {
+ // add type column default being CUSTOM (0)
+ Log_OC.i(SQL, "Add type column and default value 0 (CUSTOM) to synced_folders table");
+ db.execSQL(ALTER_TABLE + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME +
+ ADD_COLUMN + ProviderTableMeta.SYNCED_FOLDER_TYPE +
+ " INTEGER " + " DEFAULT 0");
+
+ Log_OC.i(SQL, "Add charging and wifi columns to uploads");
+ db.execSQL(ALTER_TABLE + ProviderTableMeta.UPLOADS_TABLE_NAME +
+ ADD_COLUMN + ProviderTableMeta.UPLOADS_IS_WIFI_ONLY +
+ " INTEGER " + " DEFAULT 0");
+
+ db.execSQL(ALTER_TABLE + ProviderTableMeta.UPLOADS_TABLE_NAME +
+ ADD_COLUMN + ProviderTableMeta.UPLOADS_IS_WHILE_CHARGING_ONLY +
+ " INTEGER " + " DEFAULT 0");
+
+ // create Filesystem table
+ Log_OC.i(SQL, "Create filesystem table");
+ createFileSystemTable(db);
+
+ upgraded = true;
+ db.setTransactionSuccessful();
+
+ } catch (Throwable t) {
+ Log_OC.e(TAG, "ERROR!", t);
+ } finally {
+ db.endTransaction();
+ }
+
+ if (!upgraded) {
+ Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
+ }
+ }
}
}
@@ -1135,6 +1200,8 @@ private void createUploadsTable(SQLiteDatabase db) {
+ ProviderTableMeta.UPLOADS_IS_CREATE_REMOTE_FOLDER + INTEGER // boolean
+ ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP + INTEGER
+ ProviderTableMeta.UPLOADS_LAST_RESULT + INTEGER // Upload LastResult
+ + ProviderTableMeta.UPLOADS_IS_WHILE_CHARGING_ONLY + INTEGER // boolean
+ + ProviderTableMeta.UPLOADS_IS_WIFI_ONLY + INTEGER // boolean
+ ProviderTableMeta.UPLOADS_CREATED_BY + " INTEGER );" // Upload createdBy
);
@@ -1159,7 +1226,8 @@ private void createSyncedFoldersTable(SQLiteDatabase db) {
+ ProviderTableMeta.SYNCED_FOLDER_ENABLED + " INTEGER, " // enabled
+ ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE + " INTEGER, " // subfolder by date
+ ProviderTableMeta.SYNCED_FOLDER_ACCOUNT + " TEXT, " // account
- + ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION + " INTEGER );" // upload action
+ + ProviderTableMeta.SYNCED_FOLDER_UPLOAD_ACTION + " INTEGER, " // upload action
+ + ProviderTableMeta.SYNCED_FOLDER_TYPE + " INTEGER );" // type
);
}
@@ -1170,7 +1238,7 @@ private void createExternalLinksTable(SQLiteDatabase db) {
+ ProviderTableMeta.EXTERNAL_LINKS_LANGUAGE + " TEXT, " // language
+ ProviderTableMeta.EXTERNAL_LINKS_TYPE + " INTEGER, " // type
+ ProviderTableMeta.EXTERNAL_LINKS_NAME + " TEXT, " // name
- + ProviderTableMeta.EXTERNAL_LINKS_URL + " TEXT )" // url
+ + ProviderTableMeta.EXTERNAL_LINKS_URL + " TEXT );" // url
);
}
@@ -1179,7 +1247,7 @@ private void createArbitraryData(SQLiteDatabase db) {
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id
+ ProviderTableMeta.ARBITRARY_DATA_CLOUD_ID + " TEXT, " // cloud id (account name + FQDN)
+ ProviderTableMeta.ARBITRARY_DATA_KEY + " TEXT, " // key
- + ProviderTableMeta.ARBITRARY_DATA_VALUE + " TEXT) " // value
+ + ProviderTableMeta.ARBITRARY_DATA_VALUE + " TEXT );" // value
);
}
@@ -1191,6 +1259,19 @@ private void createVirtualTable(SQLiteDatabase db) {
);
}
+ private void createFileSystemTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + ProviderTableMeta.FILESYSTEM_TABLE_NAME + "("
+ + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id
+ + ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " TEXT, "
+ + ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER + " INTEGER, "
+ + ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY + " LONG, "
+ + ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD + " INTEGER, "
+ + ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " STRING, "
+ + ProviderTableMeta.FILESYSTEM_FILE_MODIFIED + " LONG );"
+ );
+ }
+
+
/**
* Version 10 of database does not modify its scheme. It coincides with the upgrade of the ownCloud account names
* structure to include in it the path to the server instance. Updating the account names and path to local files
diff --git a/src/main/java/com/owncloud/android/services/AdvancedFileAlterationListener.java b/src/main/java/com/owncloud/android/services/AdvancedFileAlterationListener.java
deleted file mode 100644
index 9c8fa7fcc571..000000000000
--- a/src/main/java/com/owncloud/android/services/AdvancedFileAlterationListener.java
+++ /dev/null
@@ -1,237 +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;
-
-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.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 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();
- }
-}
diff --git a/src/main/java/com/owncloud/android/services/AutoUploadJob.java b/src/main/java/com/owncloud/android/services/AutoUploadJob.java
deleted file mode 100644
index 7ae6502f6e4e..000000000000
--- a/src/main/java/com/owncloud/android/services/AutoUploadJob.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Nextcloud Android client application
- *
- * @author Tobias Kaminsky
- * Copyright (C) 2017 Mario Danic
- * 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;
-
-import android.accounts.Account;
-import android.content.Context;
-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.operations.UploadFileOperation;
-import com.owncloud.android.utils.MimeTypeUtil;
-
-import java.io.File;
-
-public class AutoUploadJob extends Job {
- public static final String TAG = "AutoUploadJob";
-
- 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";
-
- @NonNull
- @Override
- protected Result onRunJob(Params params) {
- final Context context = MainApp.getAppContext();
- 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, FileUploader.LOCAL_BEHAVIOUR_FORGET);
-
-
- File file = new File(filePath);
-
-
- // File can be deleted between job generation and job execution. If file does not exist, just ignore it
- if (file.exists()) {
- final String mimeType = MimeTypeUtil.getBestMimeTypeByFilename(file.getAbsolutePath());
-
- 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
- );
- }
-
-
- return Result.SUCCESS;
- }
-}
diff --git a/src/main/java/com/owncloud/android/services/OperationsService.java b/src/main/java/com/owncloud/android/services/OperationsService.java
index 512a4a7f63a5..f9f48dc8a3ae 100644
--- a/src/main/java/com/owncloud/android/services/OperationsService.java
+++ b/src/main/java/com/owncloud/android/services/OperationsService.java
@@ -678,7 +678,7 @@ remotePath, account, syncFileContents, getApplicationContext()
// Move file/folder
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
String newParentPath = operationIntent.getStringExtra(EXTRA_NEW_PARENT_PATH);
- operation = new MoveFileOperation(remotePath, newParentPath, account);
+ operation = new MoveFileOperation(remotePath, newParentPath);
} else if (action.equals(ACTION_COPY_FILE)) {
// Copy file/folder
diff --git a/src/main/java/com/owncloud/android/services/observer/AdvancedFileAlterationObserver.java b/src/main/java/com/owncloud/android/services/observer/AdvancedFileAlterationObserver.java
deleted file mode 100644
index 86046b94596f..000000000000
--- a/src/main/java/com/owncloud/android/services/observer/AdvancedFileAlterationObserver.java
+++ /dev/null
@@ -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 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 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 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();
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/owncloud/android/services/observer/SyncedFolderObserverService.java b/src/main/java/com/owncloud/android/services/observer/SyncedFolderObserverService.java
deleted file mode 100644
index a6bd52821820..000000000000
--- a/src/main/java/com/owncloud/android/services/observer/SyncedFolderObserverService.java
+++ /dev/null
@@ -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
- *
- * 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;
-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;
- }
- }
-
-}
diff --git a/src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java b/src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java
index 01ebfd8a8f12..3a52a18124f6 100644
--- a/src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/ContactsPreferenceActivity.java
@@ -37,7 +37,7 @@
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.services.ContactsBackupJob;
+import com.owncloud.android.jobs.ContactsBackupJob;
import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.ui.fragment.contactsbackup.ContactListFragment;
import com.owncloud.android.ui.fragment.contactsbackup.ContactsBackupFragment;
diff --git a/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
index 2391ad12cdbb..4042fb0eb0c3 100644
--- a/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
@@ -211,12 +211,6 @@ protected void setupDrawer() {
setupDrawerMenu(mNavigationView);
setupQuotaElement();
-
- // show folder sync menu item only for Android 6+
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M &&
- mNavigationView.getMenu().findItem(R.id.nav_folder_sync) != null) {
- mNavigationView.getMenu().removeItem(R.id.nav_folder_sync);
- }
}
setupDrawerToggle();
@@ -366,7 +360,7 @@ public void run() {
}
if (getResources().getBoolean(R.bool.syncedFolder_light)) {
- navigationView.getMenu().removeItem(R.id.nav_folder_sync);
+ navigationView.getMenu().removeItem(R.id.nav_synced_folders);
}
if (!getResources().getBoolean(R.bool.show_drawer_logout)) {
@@ -450,9 +444,9 @@ private void selectNavigationItem(final MenuItem menuItem) {
Intent notificationsIntent = new Intent(getApplicationContext(), NotificationsActivity.class);
startActivity(notificationsIntent);
break;
- case R.id.nav_folder_sync:
- Intent folderSyncIntent = new Intent(getApplicationContext(), FolderSyncActivity.class);
- startActivity(folderSyncIntent);
+ case R.id.nav_synced_folders:
+ Intent syncedFoldersIntent = new Intent(getApplicationContext(), SyncedFoldersActivity.class);
+ startActivity(syncedFoldersIntent);
break;
case R.id.nav_contacts:
Intent contactsIntent = new Intent(getApplicationContext(), ContactsPreferenceActivity.class);
diff --git a/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java b/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java
index ccdf152a1b12..ae2f6aacffa4 100644
--- a/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java
+++ b/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java
@@ -21,7 +21,6 @@
package com.owncloud.android.ui.activity;
-import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
@@ -113,7 +112,6 @@ protected void onCreate(Bundle savedInstanceState) {
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
- final Activity activity = this;
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
webview.setWebChromeClient(new WebChromeClient() {
@@ -124,7 +122,8 @@ public void onProgressChanged(WebView view, int progress) {
webview.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- webview.loadData(DisplayUtils.getData(getResources().openRawResource(R.raw.custom_error)),"text/html; charset=UTF-8", null);
+ webview.loadData(DisplayUtils.getData(getResources().openRawResource(R.raw.custom_error)),
+ "text/html; charset=UTF-8", null);
}
});
diff --git a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
index da2b9789f201..2eb942d5ceaf 100644
--- a/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
@@ -476,7 +476,7 @@ public void showLoadingDialog(String message) {
Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
if (frag == null) {
Log_OC.d(TAG, "show loading dialog");
- LoadingDialog loading = new LoadingDialog(message);
+ LoadingDialog loading = LoadingDialog.newInstance(message);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
loading.show(ft, DIALOG_WAIT_TAG);
diff --git a/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
index c543e795b77c..102058bc4235 100644
--- a/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
@@ -282,9 +282,8 @@ public void onClick(View v) {
*/
private void upgradeNotificationForInstantUpload() {
// 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))) {
+ if (PreferenceManager.instantPictureUploadEnabled(this) ||
+ PreferenceManager.instantPictureUploadEnabled(this)) {
// remove legacy shared preferences
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit();
@@ -303,14 +302,14 @@ private void upgradeNotificationForInstantUpload() {
// show info pop-up
new AlertDialog.Builder(this, R.style.Theme_ownCloud_Dialog)
- .setTitle(R.string.drawer_folder_sync)
- .setMessage(R.string.folder_sync_new_info)
+ .setTitle(R.string.drawer_synced_folders)
+ .setMessage(R.string.synced_folders_new_info)
.setPositiveButton(R.string.drawer_open, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// show instant upload
- Intent folderSyncIntent = new Intent(getApplicationContext(), FolderSyncActivity.class);
+ Intent syncedFoldersIntent = new Intent(getApplicationContext(), SyncedFoldersActivity.class);
dialog.dismiss();
- startActivity(folderSyncIntent);
+ startActivity(syncedFoldersIntent);
}
})
.setNegativeButton(R.string.drawer_close, new DialogInterface.OnClickListener() {
@@ -318,7 +317,7 @@ public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
- .setIcon(R.drawable.nav_folder_sync)
+ .setIcon(R.drawable.nav_synced_folders)
.show();
}
}
@@ -477,7 +476,7 @@ protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if(intent.getAction()!=null && intent.getAction().equalsIgnoreCase(ACTION_DETAILS)){
setIntent(intent);
- setFile((OCFile)intent.getParcelableExtra(EXTRA_FILE));
+ setFile(intent.getParcelableExtra(EXTRA_FILE));
}
}
@@ -915,7 +914,9 @@ private void requestUploadOfFilesFromFileSystem(Intent data, int resultCode) {
null, // MIME type will be detected from file name
behaviour,
false, // do not create parent folder if not existent
- UploadFileOperation.CREATED_BY_USER
+ UploadFileOperation.CREATED_BY_USER,
+ false,
+ false
);
} else {
diff --git a/src/main/java/com/owncloud/android/ui/activity/FingerprintActivity.java b/src/main/java/com/owncloud/android/ui/activity/FingerprintActivity.java
index 0acaeac3fbc2..290964b7050c 100644
--- a/src/main/java/com/owncloud/android/ui/activity/FingerprintActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/FingerprintActivity.java
@@ -77,7 +77,6 @@ public class FingerprintActivity extends AppCompatActivity {
public final static String KEY_CHECK_RESULT = "KEY_CHECK_RESULT";
- public final static String PREFERENCE_USE_FINGERPRINT = "use_fingerprint";
public static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private KeyStore keyStore;
@@ -286,7 +285,7 @@ static public boolean isFingerprintReady(Context context) {
}
}
-@RequiresApi(Build.VERSION_CODES.M)
+@RequiresApi(api = Build.VERSION_CODES.M)
class FingerprintHandler extends FingerprintManager.AuthenticationCallback {
private TextView text;
diff --git a/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java b/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java
index 719128a13b45..54bc8748675f 100644
--- a/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java
@@ -302,6 +302,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
retval = super.onOptionsItemSelected(item);
break;
}
+
return retval;
}
diff --git a/src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java b/src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java
index 6049e02757d7..6a2fd855a9b3 100644
--- a/src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java
@@ -273,9 +273,7 @@ private String readLogFile() {
*/
public void showLoadingDialog() {
// Construct dialog
- LoadingDialog loading = new LoadingDialog(
- getResources().getString(R.string.log_progress_dialog_text)
- );
+ LoadingDialog loading = LoadingDialog.newInstance(getResources().getString(R.string.log_progress_dialog_text));
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
loading.show(ft, DIALOG_WAIT_TAG);
diff --git a/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
index a60af3c7974b..5f1b673420b5 100644
--- a/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
@@ -50,8 +50,7 @@
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.services.AccountRemovalJob;
-import com.owncloud.android.services.AutoUploadJob;
+import com.owncloud.android.jobs.AccountRemovalJob;
import com.owncloud.android.services.OperationsService;
import com.owncloud.android.ui.adapter.AccountListAdapter;
import com.owncloud.android.ui.adapter.AccountListItem;
@@ -407,7 +406,7 @@ private void performAccountRemoval(Account account) {
// store pending account removal
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
- arbitraryDataProvider.storeOrUpdateKeyValue(account, PENDING_FOR_REMOVAL, String.valueOf(true));
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PENDING_FOR_REMOVAL, String.valueOf(true));
// Cancel transfers
if (mUploaderBinder != null) {
@@ -419,7 +418,7 @@ private void performAccountRemoval(Account account) {
// schedule job
PersistableBundleCompat bundle = new PersistableBundleCompat();
- bundle.putString(AutoUploadJob.ACCOUNT, account.name);
+ bundle.putString(AccountRemovalJob.ACCOUNT, account.name);
new JobRequest.Builder(AccountRemovalJob.TAG)
.setExecutionWindow(1_000L, 10_000L)
diff --git a/src/main/java/com/owncloud/android/ui/activity/Preferences.java b/src/main/java/com/owncloud/android/ui/activity/Preferences.java
index e5c33bd9acfd..67651201a8dd 100644
--- a/src/main/java/com/owncloud/android/ui/activity/Preferences.java
+++ b/src/main/java/com/owncloud/android/ui/activity/Preferences.java
@@ -85,9 +85,11 @@
*/
public class Preferences extends PreferenceActivity
implements StorageMigration.StorageMigrationProgressListener {
-
+
private static final String TAG = Preferences.class.getSimpleName();
+ public final static String PREFERENCE_USE_FINGERPRINT = "use_fingerprint";
+
private static final String SCREEN_NAME = "Settings";
private static final int ACTION_SELECT_UPLOAD_PATH = 1;
@@ -107,6 +109,7 @@ public class Preferences extends PreferenceActivity
private SwitchPreference pCode;
private SwitchPreference fPrint;
private SwitchPreference mShowHiddenFiles;
+ private SwitchPreference mExpertMode;
private Preference pAboutApp;
private AppCompatDelegate mDelegate;
@@ -190,13 +193,14 @@ public void onCreate(Bundle savedInstanceState) {
accentColor));
// Synced folders
- PreferenceCategory preferenceCategoryFolderSync = (PreferenceCategory) findPreference("folder_sync");
- preferenceCategoryFolderSync.setTitle(ThemeUtils.getColoredTitle(getString(R.string.drawer_folder_sync),
+ PreferenceCategory preferenceCategorySyncedFolders =
+ (PreferenceCategory) findPreference("synced_folders_category");
+ preferenceCategorySyncedFolders.setTitle(ThemeUtils.getColoredTitle(getString(R.string.drawer_synced_folders),
accentColor));
PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference("preference_screen");
if (!getResources().getBoolean(R.bool.syncedFolder_light)) {
- preferenceScreen.removePreference(preferenceCategoryFolderSync);
+ preferenceScreen.removePreference(preferenceCategorySyncedFolders);
} else {
// Upload on WiFi
final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver());
@@ -209,28 +213,28 @@ public void onCreate(Bundle savedInstanceState) {
pUploadOnWifiCheckbox.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- arbitraryDataProvider.storeOrUpdateKeyValue(account, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI,
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name, SYNCED_FOLDER_LIGHT_UPLOAD_ON_WIFI,
String.valueOf(pUploadOnWifiCheckbox.isChecked()));
return true;
}
});
- Preference pSyncedFolder = findPreference("folder_sync_folders");
+ Preference pSyncedFolder = findPreference("synced_folders_configure_folders");
if (pSyncedFolder != null) {
if (getResources().getBoolean(R.bool.syncedFolder_light)
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
pSyncedFolder.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- Intent folderSyncIntent = new Intent(getApplicationContext(), FolderSyncActivity.class);
- folderSyncIntent.putExtra(FolderSyncActivity.EXTRA_SHOW_SIDEBAR, false);
- startActivity(folderSyncIntent);
+ Intent syncedFoldersIntent = new Intent(getApplicationContext(), SyncedFoldersActivity.class);
+ syncedFoldersIntent.putExtra(SyncedFoldersActivity.EXTRA_SHOW_SIDEBAR, false);
+ startActivity(syncedFoldersIntent);
return true;
}
});
} else {
- preferenceCategoryFolderSync.removePreference(pSyncedFolder);
+ preferenceCategorySyncedFolders.removePreference(pSyncedFolder);
}
}
}
@@ -265,7 +269,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
}
boolean fPrintEnabled = getResources().getBoolean(R.bool.fingerprint_enabled);
- fPrint = (SwitchPreference) findPreference(FingerprintActivity.PREFERENCE_USE_FINGERPRINT);
+ fPrint = (SwitchPreference) findPreference(PREFERENCE_USE_FINGERPRINT);
if (fPrint != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (FingerprintActivity.isFingerprintCapable(MainApp.getAppContext()) && fPrintEnabled) {
@@ -332,9 +336,21 @@ public boolean onPreferenceClick(Preference preference) {
});
} else {
preferenceCategoryDetails.removePreference(mShowHiddenFiles);
-
}
+ mExpertMode = (SwitchPreference) findPreference("expert_mode");
+ mExpertMode.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = appPrefs.edit();
+ editor.putBoolean("expert_mode", mExpertMode.isChecked());
+ editor.apply();
+ return true;
+ }
+ });
+
PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more");
preferenceCategoryMore.setTitle(ThemeUtils.getColoredTitle(getString(R.string.prefs_category_more),
accentColor));
@@ -468,7 +484,11 @@ public boolean onPreferenceClick(Preference preference) {
}
}
- boolean loggerEnabled = getResources().getBoolean(R.bool.logger_enabled) || BuildConfig.DEBUG;
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+
+ boolean loggerEnabled = getResources().getBoolean(R.bool.logger_enabled) || BuildConfig.DEBUG ||
+ appPrefs.getBoolean("expert_mode", false);
Preference pLogger = findPreference("logger");
if (pLogger != null) {
if (loggerEnabled) {
@@ -521,12 +541,12 @@ public boolean onPreferenceClick(Preference preference) {
mPrefStoragePath.setEntryValues(values);
mPrefStoragePath.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- String newPath = (String) newValue;
- if (mStoragePath.equals(newPath)) {
- return true;
- }
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String newPath = (String) newValue;
+ if (mStoragePath.equals(newPath)) {
+ return true;
+ }
StorageMigration storageMigration = new StorageMigration(Preferences.this, mStoragePath, newPath);
@@ -540,89 +560,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
}
mPrefInstantUploadCategory = (PreferenceCategory) findPreference("instant_uploading_category");
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // Instant upload via preferences on pre Android Marshmallow
- mPrefInstantUploadPath = findPreference("instant_upload_path");
- if (mPrefInstantUploadPath != null) {
-
- mPrefInstantUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- if (!mUploadPath.endsWith(OCFile.PATH_SEPARATOR)) {
- mUploadPath += OCFile.PATH_SEPARATOR;
- }
- Intent intent = new Intent(Preferences.this, UploadPathActivity.class);
- intent.putExtra(UploadPathActivity.KEY_INSTANT_UPLOAD_PATH, mUploadPath);
- startActivityForResult(intent, ACTION_SELECT_UPLOAD_PATH);
- return true;
- }
- });
- }
-
- mPrefInstantUploadCategory = (PreferenceCategory) findPreference("instant_uploading_category");
-
- mPrefInstantUploadUseSubfolders = findPreference("instant_upload_path_use_subfolders");
- mPrefInstantUploadPathWiFi = findPreference("instant_upload_on_wifi");
- mPrefInstantPictureUploadOnlyOnCharging = findPreference("instant_upload_on_charging");
- mPrefInstantUpload = (CheckBoxPreferenceWithLongTitle) findPreference("instant_uploading");
-
- toggleInstantPictureOptions(mPrefInstantUpload.isChecked());
-
- mPrefInstantUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- toggleInstantPictureOptions((Boolean) newValue);
- toggleInstantUploadBehaviour(mPrefInstantVideoUpload.isChecked(), (Boolean) newValue);
- return true;
- }
- });
-
- mPrefInstantVideoUploadPath = findPreference(PreferenceKeys.INSTANT_VIDEO_UPLOAD_PATH);
- if (mPrefInstantVideoUploadPath != null) {
-
- mPrefInstantVideoUploadPath.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- if (!mUploadVideoPath.endsWith(OCFile.PATH_SEPARATOR)) {
- mUploadVideoPath += OCFile.PATH_SEPARATOR;
- }
- Intent intent = new Intent(Preferences.this, UploadPathActivity.class);
- intent.putExtra(UploadPathActivity.KEY_INSTANT_UPLOAD_PATH,
- mUploadVideoPath);
- startActivityForResult(intent, ACTION_SELECT_UPLOAD_VIDEO_PATH);
- return true;
- }
- });
- }
-
- mPrefInstantVideoUploadUseSubfolders = findPreference("instant_video_upload_path_use_subfolders");
- mPrefInstantVideoUploadPathWiFi = findPreference("instant_video_upload_on_wifi");
- mPrefInstantVideoUpload = (CheckBoxPreferenceWithLongTitle) findPreference("instant_video_uploading");
- mPrefInstantVideoUploadOnlyOnCharging = findPreference("instant_video_upload_on_charging");
- toggleInstantVideoOptions(mPrefInstantVideoUpload.isChecked());
- mPrefInstantVideoUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- toggleInstantVideoOptions((Boolean) newValue);
- toggleInstantUploadBehaviour(
- (Boolean) newValue,
- mPrefInstantUpload.isChecked());
- return true;
- }
- });
-
- mPrefInstantUploadBehaviour = findPreference("prefs_instant_behaviour");
- toggleInstantUploadBehaviour(
- mPrefInstantVideoUpload.isChecked(),
- mPrefInstantUpload.isChecked());
-
- loadInstantUploadPath();
- loadInstantUploadVideoPath();
- } else {
- // Instant upload is handled via synced folders on Android Lollipop and up
- getPreferenceScreen().removePreference(mPrefInstantUploadCategory);
- }
+ getPreferenceScreen().removePreference(mPrefInstantUploadCategory);
// About category
PreferenceCategory preferenceCategoryAbout = (PreferenceCategory) findPreference("about");
@@ -716,48 +654,12 @@ public void run() {
mUri = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, getApplicationContext()).getBaseUri();
} catch (Throwable t) {
- Log_OC.e(TAG,"Error retrieving user's base URI", t);
+ Log_OC.e(TAG, "Error retrieving user's base URI", t);
}
}
});
t.start();
}
-
- private void toggleInstantPictureOptions(Boolean value){
- if (value) {
- mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPathWiFi);
- mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPath);
- mPrefInstantUploadCategory.addPreference(mPrefInstantUploadUseSubfolders);
- mPrefInstantUploadCategory.addPreference(mPrefInstantPictureUploadOnlyOnCharging);
- } else {
- mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi);
- mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath);
- mPrefInstantUploadCategory.removePreference(mPrefInstantUploadUseSubfolders);
- mPrefInstantUploadCategory.removePreference(mPrefInstantPictureUploadOnlyOnCharging);
- }
- }
-
- private void toggleInstantVideoOptions(Boolean value){
- if (value) {
- mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPathWiFi);
- mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPath);
- mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadUseSubfolders);
- mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadOnlyOnCharging);
- } else {
- mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi);
- mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath);
- mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadUseSubfolders);
- mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadOnlyOnCharging);
- }
- }
-
- private void toggleInstantUploadBehaviour(Boolean video, Boolean picture){
- if (picture || video) {
- mPrefInstantUploadCategory.addPreference(mPrefInstantUploadBehaviour);
- } else {
- mPrefInstantUploadCategory.removePreference(mPrefInstantUploadBehaviour);
- }
- }
@Override
protected void onResume() {
@@ -782,14 +684,14 @@ public boolean onMenuItemSelected(int featureId, MenuItem item) {
Intent intent;
switch (item.getItemId()) {
- case android.R.id.home:
- intent = new Intent(getBaseContext(), FileDisplayActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- break;
- default:
- Log_OC.w(TAG, "Unknown menu item triggered");
- return false;
+ case android.R.id.home:
+ intent = new Intent(getBaseContext(), FileDisplayActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ break;
+ default:
+ Log_OC.w(TAG, "Unknown menu item triggered");
+ return false;
}
return true;
}
@@ -800,7 +702,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ACTION_SELECT_UPLOAD_PATH && resultCode == RESULT_OK) {
- OCFile folderToUpload = data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
+ OCFile folderToUpload = data.getParcelableExtra(UploadPathActivity.EXTRA_FOLDER);
mUploadPath = folderToUpload.getRemotePath();
@@ -830,7 +732,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
.getDefaultSharedPreferences(getApplicationContext()).edit();
for (int i = 1; i <= 4; ++i) {
- appPrefs.putString(PassCodeActivity.PREFERENCE_PASSCODE_D + i, passcode.substring(i-1, i));
+ appPrefs.putString(PassCodeActivity.PREFERENCE_PASSCODE_D + i, passcode.substring(i - 1, i));
}
appPrefs.putBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, true);
appPrefs.apply();
@@ -868,10 +770,12 @@ public MenuInflater getMenuInflater() {
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
+
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
+
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
@@ -994,7 +898,7 @@ private void loadStoragePath() {
SharedPreferences appPrefs =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mStoragePath = appPrefs.getString(PreferenceKeys.STORAGE_PATH, Environment.getExternalStorageDirectory()
- .getAbsolutePath());
+ .getAbsolutePath());
String storageDescription = DataStorageProvider.getInstance().getStorageDescriptionByPath(mStoragePath);
mPrefStoragePath.setSummary(storageDescription);
}
diff --git a/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
index 7bf587335004..65947f2fccef 100755
--- a/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
@@ -913,7 +913,9 @@ public void uploadFile(String tmpname, String filename) {
FileUploader.LOCAL_BEHAVIOUR_COPY,
null,
true,
- UploadFileOperation.CREATED_BY_USER
+ UploadFileOperation.CREATED_BY_USER,
+ false,
+ false
);
finish();
}
diff --git a/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java b/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java
index 933b1e057fb9..ab6770c0f6dd 100644
--- a/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java
@@ -55,11 +55,9 @@
import java.util.ArrayList;
/**
- * Activity for sharing files
+ * Activity for sharing files.
*/
-
-public class ShareActivity extends FileActivity
- implements ShareFragmentListener {
+public class ShareActivity extends FileActivity implements ShareFragmentListener {
private static final String TAG = ShareActivity.class.getSimpleName();
@@ -70,8 +68,6 @@ public class ShareActivity extends FileActivity
/// Tags for dialog fragments
private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
- private static final String FTAG_SHARE_PASSWORD_DIALOG = "SHARE_PASSWORD_DIALOG";
-
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -87,7 +83,6 @@ protected void onCreate(Bundle savedInstanceState) {
ft.replace(R.id.share_fragment_container, fragment, TAG_SHARE_FRAGMENT);
ft.commit();
}
-
}
protected void onAccountSet(boolean stateWasRecovered) {
@@ -144,10 +139,9 @@ private void doShareWith(String shareeName, String dataAuthority) {
);
}
-
private int getAppropiatePermissions(ShareType shareType) {
- // check if the Share is FERERATED
+ // check if the Share is FEDERATED
boolean isFederated = ShareType.FEDERATED.equals(shareType);
if (getFile().isSharedWithMe()) {
@@ -245,9 +239,8 @@ && getEditShareFragment() != null && getEditShareFragment().isAdded()) {
}
-
/**
- * Updates the view, reading data from {@link com.owncloud.android.datamodel.FileDataStorageManager}
+ * Updates the view, reading data from {@link com.owncloud.android.datamodel.FileDataStorageManager}.
*/
private void refreshSharesFromStorageManager() {
@@ -270,7 +263,6 @@ private void refreshSharesFromStorageManager() {
editShareFragment.isAdded()) {
editShareFragment.refreshUiFromDB();
}
-
}
/**
@@ -300,7 +292,6 @@ private EditShareFragment getEditShareFragment() {
return (EditShareFragment) getSupportFragmentManager().findFragmentByTag(TAG_EDIT_SHARE_FRAGMENT);
}
-
private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
RemoteOperationResult result) {
if (result.isSuccess()) {
@@ -369,8 +360,5 @@ private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation ope
t.show();
}
}
-
}
-
-
}
diff --git a/src/main/java/com/owncloud/android/ui/activity/FolderSyncActivity.java b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java
similarity index 63%
rename from src/main/java/com/owncloud/android/ui/activity/FolderSyncActivity.java
rename to src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java
index c2fcb5d347e6..47c22b68a213 100644
--- a/src/main/java/com/owncloud/android/ui/activity/FolderSyncActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.java
@@ -23,56 +23,66 @@
import android.accounts.Account;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.os.Handler;
+import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
+import android.support.design.widget.AppBarLayout;
import android.support.design.widget.BottomNavigationView;
+import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.MediaFolder;
+import com.owncloud.android.datamodel.MediaFolderType;
import com.owncloud.android.datamodel.MediaProvider;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.SyncedFolder;
import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
import com.owncloud.android.datamodel.SyncedFolderProvider;
import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.ui.adapter.FolderSyncAdapter;
+import com.owncloud.android.ui.adapter.SyncedFolderAdapter;
import com.owncloud.android.ui.decoration.MediaGridItemDecoration;
import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment;
import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
import com.owncloud.android.utils.AnalyticsUtils;
import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.PermissionUtil;
import com.owncloud.android.utils.ThemeUtils;
import java.io.File;
+import java.io.FileFilter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.TimerTask;
+import static android.support.design.widget.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS;
import static com.owncloud.android.datamodel.SyncedFolderDisplayItem.UNPERSISTED_ID;
/**
* Activity displaying all auto-synced folders and/or instant upload media folders.
*/
-public class FolderSyncActivity extends FileActivity implements FolderSyncAdapter.ClickListener,
+public class SyncedFoldersActivity extends FileActivity implements SyncedFolderAdapter.ClickListener,
SyncedFolderPreferencesDialogFragment.OnSyncedFolderPreferenceListener {
private static final String SYNCED_FOLDER_PREFERENCES_DIALOG_TAG = "SYNCED_FOLDER_PREFERENCES_DIALOG";
@@ -81,16 +91,16 @@ public class FolderSyncActivity extends FileActivity implements FolderSyncAdapte
private static final String SCREEN_NAME = "Auto upload";
- private static final String TAG = FolderSyncActivity.class.getSimpleName();
+ private static final String TAG = SyncedFoldersActivity.class.getSimpleName();
private RecyclerView mRecyclerView;
- private FolderSyncAdapter mAdapter;
+ private SyncedFolderAdapter mAdapter;
private LinearLayout mProgress;
private TextView mEmpty;
private SyncedFolderProvider mSyncedFolderProvider;
- private List syncFolderItems;
private SyncedFolderPreferencesDialogFragment mSyncedFolderPreferencesDialogFragment;
private boolean showSidebar = true;
+ private RelativeLayout mCustomFolderRelativeLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -100,13 +110,37 @@ protected void onCreate(Bundle savedInstanceState) {
showSidebar = getIntent().getExtras().getBoolean(EXTRA_SHOW_SIDEBAR);
}
- setContentView(R.layout.folder_sync_layout);
+ setContentView(R.layout.synced_folders_layout);
// setup toolbar
setupToolbar();
+ CollapsingToolbarLayout mCollapsingToolbarLayout = ((CollapsingToolbarLayout)
+ findViewById(R.id.collapsing_toolbar));
+ mCollapsingToolbarLayout.setTitle(this.getString(R.string.drawer_synced_folders));
+
+ mCustomFolderRelativeLayout = (RelativeLayout) findViewById(R.id.custom_folder_toolbar);
+
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+
+
+ findViewById(R.id.toolbar).post(() -> {
+ if (!appPrefs.getBoolean("expert_mode", false)) {
+ findViewById(R.id.app_bar).getLayoutParams().height = findViewById(R.id.toolbar).getHeight();
+
+ AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) mCollapsingToolbarLayout.getLayoutParams();
+ p.setScrollFlags(SCROLL_FLAG_ENTER_ALWAYS);
+ mCollapsingToolbarLayout.setLayoutParams(p);
+ mCustomFolderRelativeLayout.setVisibility(View.GONE);
+ } else {
+ mCustomFolderRelativeLayout.setVisibility(View.VISIBLE);
+ findViewById(R.id.app_bar).setBackgroundColor(getResources().getColor(R.color.filelist_icon_backgorund));
+ }
+ });
+
// setup drawer
- setupDrawer(R.id.nav_folder_sync);
+ setupDrawer(R.id.nav_synced_folders);
if (!showSidebar) {
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
@@ -117,7 +151,7 @@ protected void onCreate(Bundle savedInstanceState) {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
- ThemeUtils.setColoredTitle(getSupportActionBar(), getString(R.string.drawer_folder_sync));
+ ThemeUtils.setColoredTitle(getSupportActionBar(), getString(R.string.drawer_synced_folders));
actionBar.setDisplayHomeAsUpEnabled(true);
}
@@ -143,7 +177,7 @@ private void setupContent() {
final int gridWidth = getResources().getInteger(R.integer.media_grid_width);
boolean lightVersion = getResources().getBoolean(R.bool.syncedFolder_light);
- mAdapter = new FolderSyncAdapter(this, gridWidth, this, lightVersion);
+ mAdapter = new SyncedFolderAdapter(this, gridWidth, this, lightVersion);
mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver());
final GridLayoutManager lm = new GridLayoutManager(this, gridWidth);
@@ -173,33 +207,25 @@ private void load(final int perFolderMediaItemLimit, boolean force) {
return;
}
setListShown(false);
- final Handler mHandler = new Handler();
- new Thread(new Runnable() {
- @Override
- public void run() {
- final List mediaFolders = MediaProvider.getMediaFolders(getContentResolver(),
- perFolderMediaItemLimit, FolderSyncActivity.this);
- 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);
- }
- }
+ final List mediaFolders = MediaProvider.getImageFolders(getContentResolver(),
+ perFolderMediaItemLimit, SyncedFoldersActivity.this);
+ mediaFolders.addAll(MediaProvider.getVideoFolders(getContentResolver(), perFolderMediaItemLimit));
+
+ List syncedFolderArrayList = mSyncedFolderProvider.getSyncedFolders();
+ List currentAccountSyncedFoldersList = new ArrayList<>();
+ Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(SyncedFoldersActivity.this);
+ for (SyncedFolder syncedFolder : syncedFolderArrayList) {
+ if (syncedFolder.getAccount().equals(currentAccount.name)) {
+ currentAccountSyncedFoldersList.add(syncedFolder);
+ }
+ }
- syncFolderItems = sortSyncedFolderItems(mergeFolderData(currentAccountSyncedFoldersList,
- mediaFolders));
+ List syncFolderItems = sortSyncedFolderItems(
+ mergeFolderData(currentAccountSyncedFoldersList, mediaFolders));
- mHandler.post(new TimerTask() {
- @Override
- public void run() {
- mAdapter.setSyncFolderItems(syncFolderItems);
- setListShown(true);
- }
- });
- }
- }).start();
+ mAdapter.setSyncFolderItems(syncFolderItems);
+ mAdapter.notifyDataSetChanged();
+ setListShown(true);
}
/**
@@ -215,20 +241,23 @@ 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));
+ if (syncedFoldersMap.containsKey(mediaFolder.absolutePath+"-"+mediaFolder.type)) {
+ SyncedFolder syncedFolder = syncedFoldersMap.get(mediaFolder.absolutePath+"-"+mediaFolder.type);
+ syncedFoldersMap.remove(mediaFolder.absolutePath+"-"+mediaFolder.type);
+
+ if (MediaFolderType.CUSTOM == syncedFolder.getType()) {
+ result.add(createSyncedFolderWithoutMediaFolder(syncedFolder));
+ } else {
+ result.add(createSyncedFolder(syncedFolder, mediaFolder));
+ }
} else {
result.add(createSyncedFolderFromMediaFolder(mediaFolder));
}
}
for (SyncedFolder syncedFolder : syncedFoldersMap.values()) {
- SyncedFolderDisplayItem syncedFolderDisplayItem = createSyncedFolderWithoutMediaFolder(syncedFolder);
- result.add(syncedFolderDisplayItem);
+ result.add(createSyncedFolderWithoutMediaFolder(syncedFolder));
}
return result;
@@ -277,6 +306,11 @@ public int compare(SyncedFolderDisplayItem f1, SyncedFolderDisplayItem f2) {
@NonNull
private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull SyncedFolder syncedFolder) {
+
+ File localFolder = new File(syncedFolder.getLocalPath());
+ File[] files = getFileList(localFolder);
+ List filePaths = getDisplayFilePathList(files);
+
return new SyncedFolderDisplayItem(
syncedFolder.getId(),
syncedFolder.getLocalPath(),
@@ -287,7 +321,10 @@ private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull Sy
syncedFolder.getAccount(),
syncedFolder.getUploadAction(),
syncedFolder.isEnabled(),
- new File(syncedFolder.getLocalPath()).getName());
+ filePaths,
+ localFolder.getName(),
+ files.length,
+ syncedFolder.getType());
}
/**
@@ -311,7 +348,8 @@ private SyncedFolderDisplayItem createSyncedFolder(@NonNull SyncedFolder syncedF
syncedFolder.isEnabled(),
mediaFolder.filePaths,
mediaFolder.folderName,
- mediaFolder.numberOfFiles);
+ mediaFolder.numberOfFiles,
+ mediaFolder.type);
}
/**
@@ -334,7 +372,42 @@ private SyncedFolderDisplayItem createSyncedFolderFromMediaFolder(@NonNull Media
false,
mediaFolder.filePaths,
mediaFolder.folderName,
- mediaFolder.numberOfFiles);
+ mediaFolder.numberOfFiles,
+ mediaFolder.type);
+ }
+
+ private File[] getFileList(File localFolder) {
+ File[] files = localFolder.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ return !pathname.isDirectory();
+ }
+ });
+
+ if (files != null) {
+ Arrays.sort(files, new Comparator() {
+ public int compare(File f1, File f2) {
+ return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
+ }
+ });
+ } else {
+ files = new File[]{};
+ }
+
+ return files;
+ }
+
+ private List getDisplayFilePathList(File[] files) {
+ List filePaths = null;
+
+ if (files != null && files.length > 0) {
+ filePaths = new ArrayList<>();
+ for (int i = 0; i < 7 && i < files.length; i++) {
+ filePaths.add(files[i].getAbsolutePath());
+ }
+ }
+
+ return filePaths;
}
/**
@@ -348,7 +421,7 @@ private Map createSyncedFoldersMap(List sync
Map result = new HashMap<>();
if (syncFolders != null) {
for (SyncedFolder syncFolder : syncFolders) {
- result.put(syncFolder.getLocalPath(), syncFolder);
+ result.put(syncFolder.getLocalPath()+"-"+syncFolder.getType(), syncFolder);
}
}
return result;
@@ -389,6 +462,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
result = super.onOptionsItemSelected(item);
break;
}
+
return result;
}
@@ -409,15 +483,27 @@ public void showFiles(boolean onDeviceOnly) {
@Override
public void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) {
+ ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext().
+ getContentResolver());
+
if (syncedFolderDisplayItem.getId() > UNPERSISTED_ID) {
- mSyncedFolderProvider.updateFolderSyncEnabled(syncedFolderDisplayItem.getId(),
+ mSyncedFolderProvider.updateSyncedFolderEnabled(syncedFolderDisplayItem.getId(),
syncedFolderDisplayItem.isEnabled());
} else {
- long storedId = mSyncedFolderProvider.storeFolderSync(syncedFolderDisplayItem);
+ long storedId = mSyncedFolderProvider.storeSyncedFolder(syncedFolderDisplayItem);
if (storedId != -1) {
syncedFolderDisplayItem.setId(storedId);
}
}
+
+ if (syncedFolderDisplayItem.isEnabled()) {
+ FilesSyncHelper.insertAllDBEntriesForSyncedFolder(syncedFolderDisplayItem);
+ } else {
+ String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + syncedFolderDisplayItem.getId();
+ arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
+ }
+ FilesSyncHelper.scheduleNJobs(false);
+
}
@Override
@@ -437,36 +523,76 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
&& resultCode == RESULT_OK && mSyncedFolderPreferencesDialogFragment != null) {
OCFile chosenFolder = data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
mSyncedFolderPreferencesDialogFragment.setRemoteFolderSummary(chosenFolder.getRemotePath());
-
- } else {
+ } if (requestCode == SyncedFolderPreferencesDialogFragment.REQUEST_CODE__SELECT_LOCAL_FOLDER
+ && resultCode == RESULT_OK && mSyncedFolderPreferencesDialogFragment != null) {
+ String localPath = data.getStringExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
+ mSyncedFolderPreferencesDialogFragment.setLocalFolderSummary(localPath);
+ }
+ else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) {
- SyncedFolderDisplayItem item = syncFolderItems.get(syncedFolder.getSection());
- boolean dirty = item.isEnabled() != syncedFolder.getEnabled();
- item = updateSyncedFolderItem(item, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder
- .getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), syncedFolder
- .getUploadAction(), syncedFolder.getEnabled());
-
- if (syncedFolder.getId() == UNPERSISTED_ID) {
- // newly set up folder sync config
- long storedId = mSyncedFolderProvider.storeFolderSync(item);
+ ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(MainApp.getAppContext().
+ getContentResolver());
+
+ // custom folders newly created aren't in the list already,
+ // so triggering a refresh
+ if (MediaFolderType.CUSTOM.equals(syncedFolder.getType()) && syncedFolder.getId() == UNPERSISTED_ID) {
+ SyncedFolderDisplayItem newCustomFolder = new SyncedFolderDisplayItem(
+ SyncedFolder.UNPERSISTED_ID, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(),
+ syncedFolder.getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(),
+ syncedFolder.getAccount(), syncedFolder.getUploadAction(), syncedFolder.getEnabled(),
+ new File(syncedFolder.getLocalPath()).getName(), syncedFolder.getType());
+ long storedId = mSyncedFolderProvider.storeSyncedFolder(newCustomFolder);
if (storedId != -1) {
- item.setId(storedId);
+ newCustomFolder.setId(storedId);
+ if (newCustomFolder.isEnabled()) {
+ FilesSyncHelper.insertAllDBEntriesForSyncedFolder(newCustomFolder);
+ } else {
+ String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + newCustomFolder.getId();
+ arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
+ }
+ FilesSyncHelper.scheduleNJobs(false);
}
-
+ mAdapter.addSyncFolderItem(newCustomFolder);
} else {
- // existing synced folder setup to be updated
- mSyncedFolderProvider.updateSyncFolder(item);
- }
- mSyncedFolderPreferencesDialogFragment = null;
+ SyncedFolderDisplayItem item = mAdapter.get(syncedFolder.getSection());
+ item = updateSyncedFolderItem(item, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder
+ .getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), syncedFolder
+ .getUploadAction(), syncedFolder.getEnabled());
+
+ if (syncedFolder.getId() == UNPERSISTED_ID) {
+ // newly set up folder sync config
+ long storedId = mSyncedFolderProvider.storeSyncedFolder(item);
+ if (storedId != -1) {
+ item.setId(storedId);
+ if (item.isEnabled()) {
+ FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item);
+ } else {
+ String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + item.getId();
+ arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
+ }
+ FilesSyncHelper.scheduleNJobs(false);
+ }
+ } else {
+ // existing synced folder setup to be updated
+ mSyncedFolderProvider.updateSyncFolder(item);
+ if (item.isEnabled()) {
+ FilesSyncHelper.insertAllDBEntriesForSyncedFolder(item);
+ } else {
+ String syncedFolderInitiatedKey = "syncedFolderIntitiated_" + item.getId();
+ arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey);
+ }
+ FilesSyncHelper.scheduleNJobs(false);
+ }
- if (dirty) {
mAdapter.setSyncFolderItem(syncedFolder.getSection(), item);
}
+
+ mSyncedFolderPreferencesDialogFragment = null;
}
@Override
@@ -474,6 +600,12 @@ public void onCancelSyncedFolderPreference() {
mSyncedFolderPreferencesDialogFragment = null;
}
+ @Override
+ public void onDeleteSyncedFolderPreference(SyncedFolderParcelable syncedFolder) {
+ mSyncedFolderProvider.deleteSyncedFolder(syncedFolder.getId());
+ mAdapter.removeItem(syncedFolder.getSection());
+ }
+
/**
* update given synced folder with the given values.
*
@@ -525,4 +657,13 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String permissi
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
+
+ public void onAddCustomFolderClick(View view) {
+ Log.d(TAG, "Show custom folder dialog");
+ SyncedFolderDisplayItem emptyCustomFolder = new SyncedFolderDisplayItem(
+ SyncedFolder.UNPERSISTED_ID, null, null, true, false,
+ false, AccountUtils.getCurrentOwnCloudAccount(this).name,
+ FileUploader.LOCAL_BEHAVIOUR_FORGET, false, null, MediaFolderType.CUSTOM);
+ onSyncFolderSettingsClick(0, emptyCustomFolder);
+ }
}
diff --git a/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java
index 049b566617b5..e8ee4f2c9461 100644
--- a/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java
@@ -27,6 +27,8 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@@ -75,6 +77,7 @@ public class UploadFilesActivity extends FileActivity implements
private ArrayAdapter mDirectories;
private File mCurrentDir = null;
private boolean mSelectAll = false;
+ private boolean mLocalFolderPickerMode = false;
private LocalFileListFragment mFileListFragment;
private Button mCancelBtn;
protected Button mUploadBtn;
@@ -88,6 +91,10 @@ public class UploadFilesActivity extends FileActivity implements
public static final String EXTRA_CHOSEN_FILES =
UploadFilesActivity.class.getCanonicalName() + ".EXTRA_CHOSEN_FILES";
+ public static final String EXTRA_ACTION = UploadFilesActivity.class.getCanonicalName() + ".EXTRA_ACTION";
+ public final static String KEY_LOCAL_FOLDER_PICKER_MODE = UploadFilesActivity.class.getCanonicalName()
+ + ".LOCAL_FOLDER_PICKER_MODE";
+
public static final int RESULT_OK_AND_MOVE = RESULT_FIRST_USER;
public static final int RESULT_OK_AND_DO_NOTHING = 2;
public static final int RESULT_OK_AND_DELETE = 3;
@@ -106,6 +113,11 @@ public void onCreate(Bundle savedInstanceState) {
Log_OC.d(TAG, "onCreate() start");
super.onCreate(savedInstanceState);
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ mLocalFolderPickerMode = extras.getBoolean(KEY_LOCAL_FOLDER_PICKER_MODE, false);
+ }
+
if(savedInstanceState != null) {
mCurrentDir = new File(savedInstanceState.getString(UploadFilesActivity.KEY_DIRECTORY_PATH, Environment
.getExternalStorageDirectory().getAbsolutePath()));
@@ -130,9 +142,14 @@ public void onCreate(Bundle savedInstanceState) {
// Inflate and set the layout view
setContentView(R.layout.upload_files_layout);
+ if (mLocalFolderPickerMode) {
+ findViewById(R.id.upload_options).setVisibility(View.GONE);
+ ((AppCompatButton) findViewById(R.id.upload_files_btn_upload))
+ .setText(R.string.uploader_btn_alternative_text);
+ }
+
mFileListFragment = (LocalFileListFragment) getSupportFragmentManager().findFragmentById(R.id.local_files_list);
-
// Set input controllers
mCancelBtn = (Button) findViewById(R.id.upload_files_btn_cancel);
mCancelBtn.setOnClickListener(this);
@@ -190,10 +207,15 @@ public static void startUploadActivityForResult(Activity activity, Account accou
public boolean onCreateOptionsMenu(Menu menu) {
mOptionsMenu = menu;
getMenuInflater().inflate(R.menu.upload_files_picker, menu);
- MenuItem selectAll = menu.findItem(R.id.action_select_all);
- setSelectAllMenuItem(selectAll, mSelectAll);
+
+ if(!mLocalFolderPickerMode) {
+ MenuItem selectAll = menu.findItem(R.id.action_select_all);
+ setSelectAllMenuItem(selectAll, mSelectAll);
+ }
+
MenuItem switchView = menu.findItem(R.id.action_switch_view);
switchView.setTitle(isGridView() ? R.string.action_switch_list_view : R.string.action_switch_grid_view);
+
return super.onCreateOptionsMenu(menu);
}
@@ -215,9 +237,6 @@ public boolean onOptionsItemSelected(MenuItem item) {
break;
}
case R.id.action_sort: {
- // Read sorting order, default to sort by name ascending
- Integer sortOrder = PreferenceManager.getSortOrder(this);
-
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.addToBackStack(null);
@@ -290,7 +309,6 @@ public boolean onNavigationItemSelected(int itemPosition, long itemId) {
}
return true;
}
-
@Override
public void onBackPressed() {
@@ -308,9 +326,10 @@ public void onBackPressed() {
}
// invalidate checked state when navigating directories
- setSelectAllMenuItem(mOptionsMenu.findItem(R.id.action_select_all), false);
+ if(!mLocalFolderPickerMode) {
+ setSelectAllMenuItem(mOptionsMenu.findItem(R.id.action_select_all), false);
+ }
}
-
@Override
protected void onSaveInstanceState(Bundle outState) {
@@ -361,15 +380,16 @@ private void setSelectAllMenuItem(MenuItem selectAll, boolean checked) {
}
}
-
- // Custom array adapter to override text colors
+ /**
+ * Custom array adapter to override text colors
+ */
private class CustomArrayAdapter extends ArrayAdapter {
public CustomArrayAdapter(UploadFilesActivity ctx, int view) {
super(ctx, view);
}
-
- public View getView(int position, View convertView, ViewGroup parent) {
+
+ public @NonNull View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View v = super.getView(position, convertView, parent);
((TextView) v).setTextColor(getResources().getColorStateList(
@@ -377,8 +397,7 @@ public View getView(int position, View convertView, ViewGroup parent) {
return v;
}
- public View getDropDownView(int position, View convertView,
- ViewGroup parent) {
+ public View getDropDownView(int position, View convertView, @NonNull ViewGroup parent) {
View v = super.getDropDownView(position, convertView, parent);
((TextView) v).setTextColor(getResources().getColorStateList(
@@ -386,7 +405,6 @@ public View getDropDownView(int position, View convertView,
return v;
}
-
}
/**
@@ -394,9 +412,11 @@ public View getDropDownView(int position, View convertView,
*/
@Override
public void onDirectoryClick(File directory) {
- // invalidate checked state when navigating directories
- MenuItem selectAll = mOptionsMenu.findItem(R.id.action_select_all);
- setSelectAllMenuItem(selectAll, false);
+ if(!mLocalFolderPickerMode) {
+ // invalidate checked state when navigating directories
+ MenuItem selectAll = mOptionsMenu.findItem(R.id.action_select_all);
+ setSelectAllMenuItem(selectAll, false);
+ }
pushDirname(directory);
ActionBar actionBar = getSupportActionBar();
@@ -419,6 +439,14 @@ public File getInitialDirectory() {
return mCurrentDir;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFolderPickerMode() {
+ return mLocalFolderPickerMode;
+ }
+
/**
* Performs corresponding action when user presses 'Cancel' or 'Upload' button
*
@@ -432,7 +460,17 @@ public void onClick(View v) {
finish();
} else if (v.getId() == R.id.upload_files_btn_upload) {
- new CheckAvailableSpaceTask().execute(mBehaviourSpinner.getSelectedItemPosition()==0);
+ if(mLocalFolderPickerMode) {
+ Intent data = new Intent();
+ if(mCurrentDir != null) {
+ data.putExtra(EXTRA_CHOSEN_FILES, mCurrentDir.getAbsolutePath());
+ }
+ setResult(RESULT_OK, data);
+
+ finish();
+ } else {
+ new CheckAvailableSpaceTask().execute(mBehaviourSpinner.getSelectedItemPosition() == 0);
+ }
}
}
@@ -445,7 +483,7 @@ public void onClick(View v) {
private class CheckAvailableSpaceTask extends AsyncTask {
/**
- * Updates the UI before trying the movement
+ * Updates the UI before trying the movement.
*/
@Override
protected void onPreExecute () {
diff --git a/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java
index 16c7949447b3..320a04fe810d 100755
--- a/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java
@@ -22,7 +22,6 @@
package com.owncloud.android.ui.activity;
import android.accounts.Account;
-import android.accounts.AccountManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -30,9 +29,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
+import android.preference.PreferenceManager;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
@@ -41,21 +42,22 @@
import android.view.View;
import android.widget.Toast;
+import com.evernote.android.job.JobRequest;
import com.owncloud.android.R;
-import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.db.OCUpload;
-import com.owncloud.android.db.UploadResult;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.jobs.FilesSyncJob;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.operations.CheckCurrentCredentialsOperation;
import com.owncloud.android.ui.fragment.UploadListFragment;
-import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.AnalyticsUtils;
+import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.MimeTypeUtil;
import java.io.File;
@@ -74,8 +76,12 @@ public class UploadListActivity extends FileActivity implements UploadListFragme
private static final String SCREEN_NAME = "Uploads";
+ private static final String EXPERT_MODE = "expert_mode";
+
private UploadMessagesReceiver mUploadMessagesReceiver;
+ private Menu mMenu;
+
@Override
public void showFiles(boolean onDeviceOnly) {
super.showFiles(onDeviceOnly);
@@ -211,9 +217,14 @@ public boolean onOptionsItemSelected(MenuItem item) {
} else {
openDrawer();
}
+ break;
+
case R.id.action_retry_uploads:
FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
requester.retryFailedUploads(this, null, null);
+ if (mMenu != null) {
+ mMenu.removeItem(R.id.action_retry_uploads);
+ }
break;
case R.id.action_clear_failed_uploads:
@@ -234,6 +245,19 @@ public boolean onOptionsItemSelected(MenuItem item) {
uploadListFragment.updateUploads();
break;
+ case R.id.action_force_rescan:
+ new JobRequest.Builder(FilesSyncJob.TAG)
+ .setExact(1_000L)
+ .setUpdateCurrent(false)
+ .build()
+ .schedule();
+
+ if (mMenu != null) {
+ mMenu.removeItem(R.id.action_force_rescan);
+ }
+
+ break;
+
default:
retval = super.onOptionsItemSelected(item);
}
@@ -243,8 +267,14 @@ public boolean onOptionsItemSelected(MenuItem item) {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.upload_list_menu, menu);
+ SharedPreferences appPrefs =
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if (appPrefs.getBoolean(EXPERT_MODE, false)) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.upload_list_menu, menu);
+ mMenu = menu;
+ }
+
return true;
}
@@ -252,17 +282,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FileActivity.REQUEST_CODE__UPDATE_CREDENTIALS && resultCode == RESULT_OK) {
- // Retry uploads of the updated account
- Account account = AccountUtils.getOwnCloudAccountByName(
- this,
- data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
- );
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.retryFailedUploads(
- this,
- account,
- UploadResult.CREDENTIAL_ERROR
- );
+ FilesSyncHelper.restartJobsIfNeeded();
}
}
@@ -283,8 +303,7 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe
} else {
// already updated -> just retry!
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.retryFailedUploads(this, account, UploadResult.CREDENTIAL_ERROR);
+ FilesSyncHelper.restartJobsIfNeeded();
}
} else {
diff --git a/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java b/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
index 3f18ad26a037..8e43c32e5f5f 100644
--- a/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
+++ b/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
@@ -63,7 +63,6 @@
import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.PushConfigurationState;
import com.owncloud.android.datamodel.SyncedFolderProvider;
-import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.lib.common.UserInfo;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@@ -410,16 +409,11 @@ public void onClick(DialogInterface dialogInterface, int i) {
contentResolver);
syncedFolderProvider.deleteSyncFoldersForAccount(account);
- UploadsStorageManager uploadsStorageManager = new UploadsStorageManager(
- contentResolver, getActivity());
- uploadsStorageManager.cancelPendingAutoUploadJobsForAccount(account);
- uploadsStorageManager.removeAccountUploads(account);
-
// disable daily backup
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(
contentResolver);
- arbitraryDataProvider.storeOrUpdateKeyValue(account,
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
"false");
@@ -433,7 +427,7 @@ public void onClick(DialogInterface dialogInterface, int i) {
PushConfigurationState pushArbitraryData = gson.fromJson(arbitraryDataPushString,
PushConfigurationState.class);
pushArbitraryData.setShouldBeDeleted(true);
- arbitraryDataProvider.storeOrUpdateKeyValue(account, PushUtils.KEY_PUSH,
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PushUtils.KEY_PUSH,
gson.toJson(pushArbitraryData));
EventBus.getDefault().post(new TokenPushEvent());
}
diff --git a/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java
index 0d9d61610bb8..ce42214e3509 100755
--- a/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java
+++ b/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java
@@ -1,21 +1,21 @@
/**
- * ownCloud Android client application
+ * ownCloud Android client application
*
- * @author LukeOwncloud
- * @author masensio
- * Copyright (C) 2016 ownCloud Inc.
+ * @author LukeOwncloud
+ * @author masensio
+ * Copyright (C) 2016 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 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.
+ * 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 .
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*/
package com.owncloud.android.ui.adapter;
@@ -26,7 +26,6 @@
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
@@ -34,7 +33,6 @@
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import android.widget.Toast;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
@@ -43,7 +41,6 @@
import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.datamodel.UploadsStorageManager.UploadStatus;
import com.owncloud.android.db.OCUpload;
-import com.owncloud.android.db.UploadResult;
import com.owncloud.android.files.services.FileUploader;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.utils.Log_OC;
@@ -102,10 +99,10 @@ public int getGroupItemCount() {
@Override
public int compare(OCUpload upload1, OCUpload upload2) {
- if (upload1 == null){
+ if (upload1 == null) {
return -1;
}
- if (upload2 == null){
+ if (upload2 == null) {
return 1;
}
if (UploadStatus.UPLOAD_IN_PROGRESS.equals(upload1.getUploadStatus())) {
@@ -153,7 +150,7 @@ public ExpandableUploadListAdapter(FileActivity parentActivity) {
mUploadGroups[0] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_current_uploads)) {
@Override
public void refresh() {
- items = mUploadsStorageManager.getCurrentAndPendingUploads();
+ items = mUploadsStorageManager.getCurrentAndPendingUploadsForCurrentAccount();
Arrays.sort(items, comparator);
}
@@ -165,7 +162,7 @@ public int getGroupIcon() {
mUploadGroups[1] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_failed_uploads)) {
@Override
public void refresh() {
- items = mUploadsStorageManager.getFailedButNotDelayedUploads();
+ items = mUploadsStorageManager.getFailedButNotDelayedUploadsForCurrentAccount();
Arrays.sort(items, comparator);
}
@@ -178,7 +175,7 @@ public int getGroupIcon() {
mUploadGroups[2] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_finished_uploads)) {
@Override
public void refresh() {
- items = mUploadsStorageManager.getFinishedUploads();
+ items = mUploadsStorageManager.getFinishedUploadsForCurrentAccount();
Arrays.sort(items, comparator);
}
@@ -292,33 +289,33 @@ private View getView(OCUpload[] uploadsItems, int position, View convertView, Vi
/// ... unbind the old progress bar, if any; ...
if (mProgressListener != null) {
binder.removeDatatransferProgressListener(
- mProgressListener,
- mProgressListener.getUpload() // the one that was added
+ mProgressListener,
+ mProgressListener.getUpload() // the one that was added
);
}
/// ... then, bind the current progress bar to listen for updates
mProgressListener = new ProgressListener(upload, progressBar);
binder.addDatatransferProgressListener(
- mProgressListener,
- upload
+ mProgressListener,
+ upload
);
} else {
/// not really uploading; stop listening progress if view is reused!
if (convertView != null &&
mProgressListener != null &&
- mProgressListener.isWrapping(progressBar)) {
+ mProgressListener.isWrapping(progressBar)) {
binder.removeDatatransferProgressListener(
- mProgressListener,
- mProgressListener.getUpload() // the one that was added
+ mProgressListener,
+ mProgressListener.getUpload() // the one that was added
);
mProgressListener = null;
}
}
} else {
Log_OC.w(
- TAG,
- "FileUploaderBinder not ready yet for upload " + upload.getRemotePath()
+ TAG,
+ "FileUploaderBinder not ready yet for upload " + upload.getRemotePath()
);
}
uploadDateTextView.setVisibility(View.GONE);
@@ -336,13 +333,14 @@ private View getView(OCUpload[] uploadsItems, int position, View convertView, Vi
}
statusTextView.setText(status);
+ /// bind listeners to perform actions
/// bind listeners to perform actions
ImageButton rightButton = (ImageButton) view.findViewById(R.id.upload_right_button);
if (upload.getUploadStatus() == UploadStatus.UPLOAD_IN_PROGRESS) {
//Cancel
rightButton.setImageResource(R.drawable.ic_action_cancel_grey);
rightButton.setVisibility(View.VISIBLE);
- rightButton.setOnClickListener(new OnClickListener() {
+ rightButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FileUploader.FileUploaderBinder uploaderBinder = mParentActivity.getFileUploaderBinder();
@@ -357,7 +355,7 @@ public void onClick(View v) {
//Delete
rightButton.setImageResource(R.drawable.ic_action_delete_grey);
rightButton.setVisibility(View.VISIBLE);
- rightButton.setOnClickListener(new OnClickListener() {
+ rightButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mUploadsStorageManager.removeUpload(upload);
@@ -368,41 +366,8 @@ public void onClick(View v) {
} else { // UploadStatus.UPLOAD_SUCCESS
rightButton.setVisibility(View.INVISIBLE);
}
-
- // retry
- if (upload.getUploadStatus() == UploadStatus.UPLOAD_FAILED) {
- if (UploadResult.CREDENTIAL_ERROR.equals(upload.getLastResult())) {
- view.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mParentActivity.getFileOperationsHelper().checkCurrentCredentials(
- upload.getAccount(mParentActivity)
- );
- }
- });
-
- } else {
- // not a credentials error
- view.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- File file = new File(upload.getLocalPath());
- if (file.exists()) {
- FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
- requester.retry(mParentActivity, upload);
- refreshView();
- } else {
- final String message = String.format(
- mParentActivity.getString(R.string.local_file_not_found_toast)
- );
- Toast.makeText(mParentActivity, message, Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- } else {
- view.setOnClickListener(null);
- }
+
+ view.setOnClickListener(null);
/// Set icon or thumbnail
ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
@@ -509,7 +474,7 @@ public void onClick(View v) {
* the given upload.
*
* @param upload Upload to describe.
- * @return Text describing the status of the given upload.
+ * @return Text describing the status of the given upload.
*/
private String getStatusText(OCUpload upload) {
@@ -533,37 +498,37 @@ private String getStatusText(OCUpload upload) {
switch (upload.getLastResult()) {
case CREDENTIAL_ERROR:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_failed_credentials_error
+ R.string.uploads_view_upload_status_failed_credentials_error
);
break;
case FOLDER_ERROR:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_failed_folder_error
+ R.string.uploads_view_upload_status_failed_folder_error
);
break;
case FILE_NOT_FOUND:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_failed_localfile_error
+ R.string.uploads_view_upload_status_failed_localfile_error
);
break;
case FILE_ERROR:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_failed_file_error
+ R.string.uploads_view_upload_status_failed_file_error
);
break;
case PRIVILEDGES_ERROR:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_failed_permission_error
+ R.string.uploads_view_upload_status_failed_permission_error
);
break;
case NETWORK_CONNECTION:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_failed_connection_error
+ R.string.uploads_view_upload_status_failed_connection_error
);
break;
case DELAYED_FOR_WIFI:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_waiting_for_wifi
+ R.string.uploads_view_upload_status_waiting_for_wifi
);
break;
case DELAYED_FOR_CHARGING:
@@ -572,32 +537,35 @@ private String getStatusText(OCUpload upload) {
break;
case CONFLICT_ERROR:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_conflict
+ R.string.uploads_view_upload_status_conflict
);
break;
case SERVICE_INTERRUPTED:
- status = mParentActivity.getString(
- R.string.uploads_view_upload_status_service_interrupted
+ status = mParentActivity.getString(
+ R.string.uploads_view_upload_status_service_interrupted
);
break;
case UNKNOWN:
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_unknown_fail
+ R.string.uploads_view_upload_status_unknown_fail
);
break;
case CANCELLED:
// should not get here ; cancelled uploads should be wiped out
status = mParentActivity.getString(
- R.string.uploads_view_upload_status_cancelled
+ R.string.uploads_view_upload_status_cancelled
);
break;
case UPLOADED:
// should not get here ; status should be UPLOAD_SUCCESS
- status = mParentActivity.getString(R.string.uploads_view_upload_status_succeeded);
+ status = mParentActivity.getString(R.string.uploads_view_upload_status_succeeded);
break;
case MAINTENANCE_MODE:
status = mParentActivity.getString(R.string.maintenance_mode);
break;
+ case LOCK_FAILED:
+ status = mParentActivity.getString(R.string.lock_failed);
+ break;
default:
status = "Naughty devs added a new fail result but no description for the user";
break;
@@ -747,8 +715,8 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, lo
public boolean isWrapping(ProgressBar progressBar) {
ProgressBar wrappedProgressBar = mProgressBar.get();
return (
- wrappedProgressBar != null &&
- wrappedProgressBar == progressBar // on purpose; don't replace with equals
+ wrappedProgressBar != null &&
+ wrappedProgressBar == progressBar // on purpose; don't replace with equals
);
}
diff --git a/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
index 69f036585bea..01a683642318 100644
--- a/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
+++ b/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
@@ -41,6 +41,7 @@
import com.owncloud.android.utils.MimeTypeUtil;
import java.io.File;
+import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -58,10 +59,12 @@ public class LocalFileListAdapter extends BaseAdapter implements FilterableListA
private Context mContext;
private File[] mFiles = null;
- private Vector mFilesAll = new Vector();
+ private Vector mFilesAll = new Vector<>();
+ private boolean mLocalFolderPicker;
- public LocalFileListAdapter(File directory, Context context) {
+ public LocalFileListAdapter(boolean localFolderPickerMode, File directory, Context context) {
mContext = context;
+ mLocalFolderPicker = localFolderPickerMode;
// Read sorting order, default to sort by name ascending
FileStorageUtils.mSortOrder = PreferenceManager.getSortOrder(context);
@@ -272,7 +275,11 @@ public boolean isEmpty() {
* @param directory New file to adapt. Can be NULL, meaning "no content to adapt".
*/
public void swapDirectory(final File directory) {
- mFiles = (directory != null ? directory.listFiles() : null);
+ if(mLocalFolderPicker) {
+ mFiles = (directory != null ? getFolders(directory) : null);
+ } else {
+ mFiles = (directory != null ? directory.listFiles() : null);
+ }
if (mFiles != null) {
Arrays.sort(mFiles, new Comparator() {
@Override
@@ -288,7 +295,6 @@ public int compare(File lhs, File rhs) {
private int compareNames(File lhs, File rhs) {
return lhs.getName().toLowerCase().compareTo(rhs.getName().toLowerCase());
}
-
});
mFiles = FileStorageUtils.sortLocalFolder(mFiles);
@@ -317,6 +323,15 @@ public void setSortOrder(Integer order, boolean ascending) {
notifyDataSetChanged();
}
+ private File[] getFolders(final File directory) {
+ return directory.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ return file.isDirectory();
+ }
+ });
+ }
+
public void filter(String text){
if(text.isEmpty()){
mFiles = mFilesAll.toArray(new File[1]);
diff --git a/src/main/java/com/owncloud/android/ui/adapter/FolderSyncAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java
similarity index 64%
rename from src/main/java/com/owncloud/android/ui/adapter/FolderSyncAdapter.java
rename to src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java
index 92ca34aefd0d..d564e596217a 100644
--- a/src/main/java/com/owncloud/android/ui/adapter/FolderSyncAdapter.java
+++ b/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.java
@@ -1,22 +1,22 @@
/**
* Nextcloud Android client application
*
- * @author Andy Scherzinger
- * Copyright (C) 2016 Andy Scherzinger
- * Copyright (C) 2016 Nextcloud
+ * @author Andy Scherzinger
+ * Copyright (C) 2016 Andy Scherzinger
+ * 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 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.
+ * 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 .
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see .
*/
package com.owncloud.android.ui.adapter;
@@ -29,10 +29,12 @@
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter;
import com.owncloud.android.R;
+import com.owncloud.android.datamodel.MediaFolderType;
import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
import com.owncloud.android.utils.ThemeUtils;
@@ -44,7 +46,7 @@
/**
* Adapter to display all auto-synced folders and/or instant upload media folders.
*/
-public class FolderSyncAdapter extends SectionedRecyclerViewAdapter {
+public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter {
private final Context mContext;
private final int mGridWidth;
@@ -53,19 +55,20 @@ public class FolderSyncAdapter extends SectionedRecyclerViewAdapter mSyncFolderItems;
private final boolean mLight;
- public FolderSyncAdapter(Context context, int gridWidth, ClickListener listener, boolean light) {
+ public SyncedFolderAdapter(Context context, int gridWidth, ClickListener listener, boolean light) {
mContext = context;
mGridWidth = gridWidth;
mGridTotal = gridWidth * 2;
mListener = listener;
mSyncFolderItems = new ArrayList<>();
mLight = light;
+
+ shouldShowHeadersForEmptySections(true);
}
public void setSyncFolderItems(List syncFolderItems) {
mSyncFolderItems.clear();
mSyncFolderItems.addAll(syncFolderItems);
- notifyDataSetChanged();
}
public void setSyncFolderItem(int location, SyncedFolderDisplayItem syncFolderItem) {
@@ -73,6 +76,16 @@ public void setSyncFolderItem(int location, SyncedFolderDisplayItem syncFolderIt
notifyDataSetChanged();
}
+ public void addSyncFolderItem(SyncedFolderDisplayItem syncFolderItem) {
+ mSyncFolderItems.add(syncFolderItem);
+ notifyDataSetChanged();
+ }
+
+ public void removeItem(int section) {
+ mSyncFolderItems.remove(section);
+ notifyDataSetChanged();
+ }
+
@Override
public int getSectionCount() {
return mSyncFolderItems.size();
@@ -87,18 +100,39 @@ public int getItemCount(int section) {
}
}
+ public SyncedFolderDisplayItem get(int section) {
+ return mSyncFolderItems.get(section);
+ }
+
@Override
public void onBindHeaderViewHolder(final MainViewHolder holder, final int section) {
+ holder.mainHeaderContainer.setVisibility(View.VISIBLE);
+
holder.title.setText(mSyncFolderItems.get(section).getFolderName());
+
+ if (MediaFolderType.VIDEO == mSyncFolderItems.get(section).getType()) {
+ holder.type.setImageResource(R.drawable.ic_video_18dp);
+ } else if (MediaFolderType.IMAGE == mSyncFolderItems.get(section).getType()) {
+ holder.type.setImageResource(R.drawable.ic_image_18dp);
+ } else {
+ holder.type.setImageResource(R.drawable.ic_folder_star_18dp);
+ }
+
holder.syncStatusButton.setVisibility(View.VISIBLE);
holder.syncStatusButton.setTag(section);
- holder.syncStatusButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled());
- setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
- mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section));
- }
+ holder.syncStatusButton.setOnClickListener(v -> {
+ mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled());
+ setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
+ mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section));
+ });
+ setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
+
+ holder.syncStatusButton.setVisibility(View.VISIBLE);
+ holder.syncStatusButton.setTag(section);
+ holder.syncStatusButton.setOnClickListener(v -> {
+ mSyncFolderItems.get(section).setEnabled(!mSyncFolderItems.get(section).isEnabled());
+ setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
+ mListener.onSyncStatusToggleClick(section, mSyncFolderItems.get(section));
});
setSyncButtonActiveIcon(holder.syncStatusButton, mSyncFolderItems.get(section).isEnabled());
@@ -107,18 +141,14 @@ public void onClick(View v) {
} else {
holder.menuButton.setVisibility(View.VISIBLE);
holder.menuButton.setTag(section);
- holder.menuButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mListener.onSyncFolderSettingsClick(section, mSyncFolderItems.get(section));
- }
- });
+ holder.menuButton.setOnClickListener(v -> mListener.onSyncFolderSettingsClick(section,
+ mSyncFolderItems.get(section)));
}
}
+
@Override
public void onBindViewHolder(MainViewHolder holder, int section, int relativePosition, int absolutePosition) {
-
if (mSyncFolderItems.get(section).getFilePaths() != null) {
File file = new File(mSyncFolderItems.get(section).getFilePaths().get(relativePosition));
@@ -148,14 +178,6 @@ public void onBindViewHolder(MainViewHolder holder, int section, int relativePos
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);
- } else {
- holder.itemView.setTag(relativePosition % mGridWidth);
- holder.counterValue.setText(Long.toString(0));
- holder.counterBar.setVisibility(View.VISIBLE);
- holder.thumbnailDarkener.setVisibility(View.VISIBLE);
}
}
@@ -163,7 +185,7 @@ public void onBindViewHolder(MainViewHolder holder, int section, int relativePos
public MainViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(
viewType == VIEW_TYPE_HEADER ?
- R.layout.folder_sync_item_header : R.layout.grid_sync_item, parent, false);
+ R.layout.synced_folders_item_header : R.layout.grid_sync_item, parent, false);
return new MainViewHolder(v);
}
@@ -175,16 +197,21 @@ public interface ClickListener {
static class MainViewHolder extends RecyclerView.ViewHolder {
private final ImageView image;
private final TextView title;
+ private final ImageView type;
private final ImageButton menuButton;
private final ImageButton syncStatusButton;
private final LinearLayout counterBar;
private final TextView counterValue;
private final ImageView thumbnailDarkener;
+ private final RelativeLayout mainHeaderContainer;
+
private MainViewHolder(View itemView) {
super(itemView);
+ mainHeaderContainer = (RelativeLayout) itemView.findViewById(R.id.header_container);
image = (ImageView) itemView.findViewById(R.id.thumbnail);
title = (TextView) itemView.findViewById(R.id.title);
+ type = (ImageView) itemView.findViewById(R.id.type);
menuButton = (ImageButton) itemView.findViewById(R.id.settingsButton);
syncStatusButton = (ImageButton) itemView.findViewById(R.id.syncStatusButton);
counterBar = (LinearLayout) itemView.findViewById(R.id.counterLayout);
@@ -194,7 +221,7 @@ private MainViewHolder(View itemView) {
}
private void setSyncButtonActiveIcon(ImageButton syncStatusButton, boolean enabled) {
- if(enabled) {
+ if (enabled) {
syncStatusButton.setImageDrawable(ThemeUtils.tintDrawable(R.drawable.ic_cloud_sync_on,
ThemeUtils.primaryColor()));
} else {
diff --git a/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java b/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java
index 1ed1b02a34f5..f60552ebfbbe 100644
--- a/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java
+++ b/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java
@@ -228,7 +228,9 @@ private void requestUpload(Account account, String localPath, String remotePath,
behaviour,
mimeType,
false, // do not create parent folder if not existent
- UploadFileOperation.CREATED_BY_USER
+ UploadFileOperation.CREATED_BY_USER,
+ false,
+ false
);
}
diff --git a/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java b/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java
index aec8ce5dc4f5..d48937979d8e 100644
--- a/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java
+++ b/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java
@@ -47,8 +47,10 @@ public void onCreate(Bundle savedInstanceState) {
setCancelable(false);
}
- public LoadingDialog(String message) {
- this.mMessage = message;
+ public static LoadingDialog newInstance(String message) {
+ LoadingDialog loadingDialog = new LoadingDialog();
+ loadingDialog.mMessage = message;
+ return loadingDialog;
}
@Override
diff --git a/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java b/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java
index 7f6ef0382df2..8f01e4fa16dc 100644
--- a/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java
+++ b/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java
@@ -105,7 +105,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
mView = inflater.inflate(R.layout.sorting_order_fragment, container, false);
setupDialogElements(mView);
- setupListeners(mView);
+ setupListeners();
return mView;
}
@@ -208,10 +208,8 @@ private void colorActiveSortingIconAndText(ImageButton imageButton, TextView tex
/**
* setup all listeners.
- *
- * @param view the parent view
*/
- private void setupListeners(View view) {
+ private void setupListeners() {
mCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
diff --git a/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java b/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java
index 772746f86ac1..672a08d1841c 100644
--- a/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java
+++ b/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java
@@ -25,6 +25,7 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -41,13 +42,19 @@
import android.widget.TextView;
import com.owncloud.android.R;
+import com.owncloud.android.datamodel.MediaFolderType;
import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.ui.activity.FolderPickerActivity;
+import com.owncloud.android.ui.activity.UploadFilesActivity;
import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ThemeUtils;
+import java.io.File;
+
+import static com.owncloud.android.datamodel.SyncedFolderDisplayItem.UNPERSISTED_ID;
+
/**
* Dialog to show the preferences/configuration of a synced folder allowing the user to change the different parameters.
*/
@@ -57,6 +64,7 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment {
public static final String SYNCED_FOLDER_PARCELABLE = "SyncedFolderParcelable";
private static final String BEHAVIOUR_DIALOG_STATE = "BEHAVIOUR_DIALOG_STATE";
public static final int REQUEST_CODE__SELECT_REMOTE_FOLDER = 0;
+ public static final int REQUEST_CODE__SELECT_LOCAL_FOLDER = 1;
private CharSequence[] mUploadBehaviorItemStrings;
@@ -67,6 +75,7 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment {
private AppCompatCheckBox mUploadUseSubfoldersCheckbox;
private TextView mUploadBehaviorSummary;
private TextView mLocalFolderPath;
+ private TextView mLocalFolderSummary;
private TextView mRemoteFolderSummary;
private SyncedFolderParcelable mSyncedFolder;
@@ -85,7 +94,7 @@ public static SyncedFolderPreferencesDialogFragment newInstance(SyncedFolderDisp
Bundle args = new Bundle();
args.putParcelable(SYNCED_FOLDER_PARCELABLE, new SyncedFolderParcelable(syncedFolder, section));
dialogFragment.setArguments(args);
- dialogFragment.setStyle(STYLE_NORMAL,R.style.Theme_ownCloud_Dialog);
+ dialogFragment.setStyle(STYLE_NORMAL, R.style.Theme_ownCloud_Dialog);
return dialogFragment;
}
@@ -116,7 +125,7 @@ public void onCreate(Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log_OC.d(TAG, "onCreateView, savedInstanceState is " + savedInstanceState);
- mView = inflater.inflate(R.layout.folder_sync_settings_layout, container, false);
+ mView = inflater.inflate(R.layout.synced_folders_settings_layout, container, false);
setupDialogElements(mView);
setupListeners(mView);
@@ -132,20 +141,49 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
private void setupDialogElements(View view) {
int accentColor = ThemeUtils.primaryAccentColor();
+ if (mSyncedFolder.getType().getId() > MediaFolderType.CUSTOM.getId()) {
+ // hide local folder chooser and delete for non-custom folders
+ view.findViewById(R.id.local_folder_container).setVisibility(View.GONE);
+ view.findViewById(R.id.delete).setVisibility(View.GONE);
+ } else if (mSyncedFolder.getId() <= UNPERSISTED_ID) {
+ // Hide delete/enabled for unpersisted custom folders
+ view.findViewById(R.id.delete).setVisibility(View.GONE);
+ view.findViewById(R.id.sync_enabled).setVisibility(View.GONE);
+
+ // auto set custom folder to enabled
+ mSyncedFolder.setEnabled(true);
+
+ // switch text to create headline
+ ((TextView) view.findViewById(R.id.synced_folders_settings_title))
+ .setText(R.string.autoupload_create_new_custom_folder);
+
+ // disable save button
+ view.findViewById(R.id.save).setEnabled(false);
+ } else {
+ view.findViewById(R.id.local_folder_container).setVisibility(View.GONE);
+ }
+
// find/saves UI elements
mEnabledSwitch = (SwitchCompat) view.findViewById(R.id.sync_enabled);
ThemeUtils.tintSwitch(mEnabledSwitch, accentColor);
- mLocalFolderPath = (TextView) view.findViewById(R.id.folder_sync_settings_local_folder_path);
+ mLocalFolderPath = (TextView) view.findViewById(R.id.synced_folders_settings_local_folder_path);
+ mLocalFolderSummary = (TextView) view.findViewById(R.id.local_folder_summary);
mRemoteFolderSummary = (TextView) view.findViewById(R.id.remote_folder_summary);
mUploadOnWifiCheckbox = (AppCompatCheckBox) view.findViewById(R.id.setting_instant_upload_on_wifi_checkbox);
ThemeUtils.tintCheckbox(mUploadOnWifiCheckbox, accentColor);
- mUploadOnChargingCheckbox = (AppCompatCheckBox) view.findViewById(
- R.id.setting_instant_upload_on_charging_checkbox);
- ThemeUtils.tintCheckbox(mUploadOnChargingCheckbox, accentColor);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ view.findViewById(R.id.setting_instant_upload_on_charging_container).setVisibility(View.GONE);
+ } else {
+ view.findViewById(R.id.setting_instant_upload_on_charging_container).setVisibility(View.VISIBLE);
+
+ mUploadOnChargingCheckbox = (AppCompatCheckBox) view.findViewById(
+ R.id.setting_instant_upload_on_charging_checkbox);
+ ThemeUtils.tintCheckbox(mUploadOnChargingCheckbox, accentColor);
+ }
mUploadUseSubfoldersCheckbox = (AppCompatCheckBox) view.findViewById(
R.id.setting_instant_upload_path_use_subfolders_checkbox);
@@ -161,18 +199,30 @@ private void setupDialogElements(View view) {
// Set values
setEnabled(mSyncedFolder.getEnabled());
- mLocalFolderPath.setText(
- DisplayUtils.createTextWithSpan(
- String.format(
- getString(R.string.folder_sync_preferences_folder_path),
- mSyncedFolder.getLocalPath()),
- mSyncedFolder.getFolderName(),
- new StyleSpan(Typeface.BOLD)));
- mRemoteFolderSummary.setText(mSyncedFolder.getRemotePath());
+ if (mSyncedFolder.getLocalPath() != null && mSyncedFolder.getLocalPath().length() > 0) {
+ mLocalFolderPath.setText(
+ DisplayUtils.createTextWithSpan(
+ String.format(
+ getString(R.string.synced_folders_preferences_folder_path),
+ mSyncedFolder.getLocalPath()),
+ mSyncedFolder.getFolderName(),
+ new StyleSpan(Typeface.BOLD)));
+ mLocalFolderSummary.setText(mSyncedFolder.getLocalPath());
+ } else {
+ mLocalFolderSummary.setText(R.string.choose_local_folder);
+ }
+
+ if (mSyncedFolder.getLocalPath() != null && mSyncedFolder.getLocalPath().length() > 0) {
+ mRemoteFolderSummary.setText(mSyncedFolder.getRemotePath());
+ } else {
+ mRemoteFolderSummary.setText(R.string.choose_remote_folder);
+ }
mUploadOnWifiCheckbox.setChecked(mSyncedFolder.getWifiOnly());
- mUploadOnChargingCheckbox.setChecked(mSyncedFolder.getChargingOnly());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ mUploadOnChargingCheckbox.setChecked(mSyncedFolder.getChargingOnly());
+ }
mUploadUseSubfoldersCheckbox.setChecked(mSyncedFolder.getSubfolderByDate());
mUploadBehaviorSummary.setText(mUploadBehaviorItemStrings[mSyncedFolder.getUploadActionInteger()]);
@@ -198,6 +248,35 @@ private void setEnabled(boolean enabled) {
public void setRemoteFolderSummary(String path) {
mSyncedFolder.setRemotePath(path);
mRemoteFolderSummary.setText(path);
+ checkAndUpdateSaveButtonState();
+ }
+
+ /**
+ * set (new) local path on activity result of the folder picker activity. The result gets originally propagated
+ * to the underlying activity since the picker is an activity and the result can't get passed to the dialog
+ * fragment directly.
+ *
+ * @param path the remote path to be set
+ */
+ public void setLocalFolderSummary(String path) {
+ mSyncedFolder.setLocalPath(path);
+ mLocalFolderSummary.setText(path);
+ mLocalFolderPath.setText(
+ DisplayUtils.createTextWithSpan(
+ String.format(
+ getString(R.string.synced_folders_preferences_folder_path),
+ mSyncedFolder.getLocalPath()),
+ new File(mSyncedFolder.getLocalPath()).getName(),
+ new StyleSpan(Typeface.BOLD)));
+ checkAndUpdateSaveButtonState();
+ }
+
+ private void checkAndUpdateSaveButtonState() {
+ if (mSyncedFolder.getLocalPath() != null && mSyncedFolder.getRemotePath() != null) {
+ mView.findViewById(R.id.save).setEnabled(true);
+ } else {
+ mView.findViewById(R.id.save).setEnabled(false);
+ }
}
/**
@@ -208,6 +287,7 @@ public void setRemoteFolderSummary(String path) {
private void setupListeners(View view) {
mSave.setOnClickListener(new OnSyncedFolderSaveClickListener());
mCancel.setOnClickListener(new OnSyncedFolderCancelClickListener());
+ view.findViewById(R.id.delete).setOnClickListener(new OnSyncedFolderDeleteClickListener());
view.findViewById(R.id.setting_instant_upload_on_wifi_container).setOnClickListener(
new OnClickListener() {
@@ -218,14 +298,17 @@ public void onClick(View v) {
}
});
- view.findViewById(R.id.setting_instant_upload_on_charging_container).setOnClickListener(
- new OnClickListener() {
- @Override
- public void onClick(View v) {
- mSyncedFolder.setChargingOnly(!mSyncedFolder.getChargingOnly());
- mUploadOnChargingCheckbox.toggle();
- }
- });
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+
+ view.findViewById(R.id.setting_instant_upload_on_charging_container).setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mSyncedFolder.setChargingOnly(!mSyncedFolder.getChargingOnly());
+ mUploadOnChargingCheckbox.toggle();
+ }
+ });
+ }
view.findViewById(R.id.setting_instant_upload_path_use_subfolders_container).setOnClickListener(
new OnClickListener() {
@@ -240,12 +323,19 @@ public void onClick(View v) {
@Override
public void onClick(View v) {
Intent action = new Intent(getActivity(), FolderPickerActivity.class);
- action.putExtra(
- FolderPickerActivity.EXTRA_ACTION, getResources().getText(R.string.choose_remote_folder));
getActivity().startActivityForResult(action, REQUEST_CODE__SELECT_REMOTE_FOLDER);
}
});
+ view.findViewById(R.id.local_folder_container).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent action = new Intent(getActivity(), UploadFilesActivity.class);
+ action.putExtra(UploadFilesActivity.KEY_LOCAL_FOLDER_PICKER_MODE, true);
+ getActivity().startActivityForResult(action, REQUEST_CODE__SELECT_LOCAL_FOLDER);
+ }
+ });
+
view.findViewById(R.id.sync_enabled).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -330,10 +420,20 @@ public void onClick(View v) {
}
}
+ private class OnSyncedFolderDeleteClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ dismiss();
+ ((OnSyncedFolderPreferenceListener) getActivity()).onDeleteSyncedFolderPreference(mSyncedFolder);
+ }
+ }
+
public interface OnSyncedFolderPreferenceListener {
void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder);
void onCancelSyncedFolderPreference();
+
+ void onDeleteSyncedFolderPreference(SyncedFolderParcelable syncedFolder);
}
@Override
diff --git a/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java b/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java
index f5d9f499ba57..d03922b76921 100644
--- a/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java
+++ b/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.owncloud.android.datamodel.MediaFolderType;
import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
import com.owncloud.android.files.services.FileUploader;
@@ -38,6 +39,7 @@ public class SyncedFolderParcelable implements Parcelable {
private Boolean mEnabled = false;
private Boolean mSubfolderByDate = false;
private Integer mUploadAction;
+ private MediaFolderType mType;
private long mId;
private String mAccount;
private int mSection;
@@ -54,6 +56,7 @@ public SyncedFolderParcelable(SyncedFolderDisplayItem syncedFolderDisplayItem, i
mChargingOnly = syncedFolderDisplayItem.getChargingOnly();
mEnabled = syncedFolderDisplayItem.isEnabled();
mSubfolderByDate = syncedFolderDisplayItem.getSubfolderByDate();
+ mType = syncedFolderDisplayItem.getType();
mAccount = syncedFolderDisplayItem.getAccount();
mUploadAction = syncedFolderDisplayItem.getUploadAction();
mSection = section;
@@ -68,6 +71,7 @@ private SyncedFolderParcelable(Parcel read) {
mChargingOnly = read.readInt() != 0;
mEnabled = read.readInt() != 0;
mSubfolderByDate = read.readInt() != 0;
+ mType = MediaFolderType.getById(read.readInt());
mAccount = read.readString();
mUploadAction = read.readInt();
mSection = read.readInt();
@@ -83,6 +87,7 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mChargingOnly ? 1 : 0);
dest.writeInt(mEnabled ? 1 : 0);
dest.writeInt(mSubfolderByDate ? 1 : 0);
+ dest.writeInt(mType.getId());
dest.writeString(mAccount);
dest.writeInt(mUploadAction);
dest.writeInt(mSection);
@@ -163,6 +168,14 @@ public void setSubfolderByDate(Boolean mSubfolderByDate) {
this.mSubfolderByDate = mSubfolderByDate;
}
+ public MediaFolderType getType() {
+ return mType;
+ }
+
+ public void setType(MediaFolderType mType) {
+ this.mType = mType;
+ }
+
public Integer getUploadAction() {
return mUploadAction;
}
diff --git a/src/main/java/com/owncloud/android/services/ShutdownReceiver.java b/src/main/java/com/owncloud/android/ui/events/InitiateSyncedFolder.java
similarity index 56%
rename from src/main/java/com/owncloud/android/services/ShutdownReceiver.java
rename to src/main/java/com/owncloud/android/ui/events/InitiateSyncedFolder.java
index 940dd1e45ed5..0526061435f5 100644
--- a/src/main/java/com/owncloud/android/services/ShutdownReceiver.java
+++ b/src/main/java/com/owncloud/android/ui/events/InitiateSyncedFolder.java
@@ -3,7 +3,6 @@
*
* @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
@@ -18,23 +17,19 @@
* 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;
+package com.owncloud.android.ui.events;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
+import com.owncloud.android.datamodel.SyncedFolder;
-import com.owncloud.android.MainApp;
+public class InitiateSyncedFolder {
+ private final SyncedFolder syncedFolder;
-/**
- * Handles shutdown procedure - basically just waits a little bit for all jobs to finish
- */
-public class ShutdownReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(final Context context, final Intent intent) {
- if (MainApp.getSyncedFolderObserverService() != null) {
- MainApp.getSyncedFolderObserverService().onDestroy();
- }
+ public InitiateSyncedFolder(SyncedFolder syncedFolder) {
+ this.syncedFolder = syncedFolder;
+ }
+
+ public SyncedFolder getSyncedFolder() {
+ return syncedFolder;
}
}
diff --git a/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java b/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java
index 50efa6ceca00..26ec97cd2027 100644
--- a/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java
+++ b/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java
@@ -955,7 +955,7 @@ public void onConfigurationChanged(Configuration newConfig) {
maxColumnSize = maxColumnSizePortrait;
}
- if (mGridView.getNumColumns() > maxColumnSize) {
+ if (mGridView != null && mGridView.getNumColumns() > maxColumnSize) {
mGridView.setNumColumns(maxColumnSize);
mGridView.invalidateViews();
}
diff --git a/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java
index 675cb6bbe555..4c718e3f8055 100644
--- a/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java
+++ b/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java
@@ -26,6 +26,8 @@
import android.os.Environment;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
@@ -89,7 +91,6 @@ public void onAttach(Activity activity) {
}
}
-
/**
* {@inheritDoc}
*/
@@ -97,11 +98,19 @@ public void onAttach(Activity activity) {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log_OC.i(TAG, "onCreateView() start");
View v = super.onCreateView(inflater, container, savedInstanceState);
- setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+
+ if(!mContainerActivity.isFolderPickerMode()) {
+ setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ setMessageForEmptyList(R.string.file_list_empty_headline, R.string.local_file_list_empty,
+ R.drawable.ic_list_empty_folder, true);
+ } else {
+ setMessageForEmptyList(R.string.folder_list_empty_headline, R.string.local_folder_list_empty,
+ R.drawable.ic_list_empty_folder, true);
+ }
+
setSwipeEnabled(false); // Disable pull-to-refresh
setFabEnabled(false); // Disable FAB
- setMessageForEmptyList(R.string.file_list_empty_headline, R.string.local_file_list_empty,
- R.drawable.ic_list_empty_folder, true);
+
Log_OC.i(TAG, "onCreateView() end");
return v;
}
@@ -115,11 +124,29 @@ public void onActivityCreated(Bundle savedInstanceState) {
Log_OC.i(TAG, "onActivityCreated() start");
super.onActivityCreated(savedInstanceState);
- mAdapter = new LocalFileListAdapter(mContainerActivity.getInitialDirectory(), getActivity());
+
+ mAdapter = new LocalFileListAdapter(
+ mContainerActivity.isFolderPickerMode(),
+ mContainerActivity.getInitialDirectory(),
+ getActivity()
+ );
setListAdapter(mAdapter);
Log_OC.i(TAG, "onActivityCreated() stop");
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if (mContainerActivity.isFolderPickerMode()) {
+ menu.removeItem(R.id.action_select_all);
+ menu.removeItem(R.id.action_search);
+ } else {
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+ }
/**
* Checks the file clicked over. Browses inside if it is a directory.
@@ -303,8 +330,7 @@ public interface ContainerActivity {
* @param file
*/
void onFileClick(File file);
-
-
+
/**
* Callback method invoked when the parent activity
* is fully created to get the directory to list firstly.
@@ -313,6 +339,13 @@ public interface ContainerActivity {
*/
File getInitialDirectory();
+ /**
+ * config check if the list should behave in
+ * folder picker mode only displaying folders but no files.
+ *
+ * @return true if folder picker mode, else false
+ */
+ boolean isFolderPickerMode();
}
diff --git a/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java b/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java
index 2b8c16d150c0..dcda8f6b8420 100644
--- a/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java
+++ b/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactListFragment.java
@@ -67,7 +67,7 @@
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileDownloader;
import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.services.ContactsImportJob;
+import com.owncloud.android.jobs.ContactsImportJob;
import com.owncloud.android.ui.TextDrawable;
import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
import com.owncloud.android.ui.events.VCardToggleEvent;
diff --git a/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java b/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java
index 959d87de91d0..49832fa71dc2 100644
--- a/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java
+++ b/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/ContactsBackupFragment.java
@@ -49,9 +49,9 @@
import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.jobs.ContactsBackupJob;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.operations.RefreshFolderOperation;
-import com.owncloud.android.services.ContactsBackupJob;
import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
import com.owncloud.android.ui.activity.Preferences;
import com.owncloud.android.ui.fragment.FileFragment;
@@ -338,7 +338,7 @@ private void setAutomaticBackup(final boolean bool) {
contactsPreferenceActivity.getAccount());
}
- arbitraryDataProvider.storeOrUpdateKeyValue(account, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
String.valueOf(bool));
}
diff --git a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
index b4ac3ccd71f4..84f7b3e4f1be 100755
--- a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
+++ b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
@@ -176,7 +176,7 @@ public void openFile(OCFile file) {
openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
List launchables = mFileActivity.getPackageManager().
- queryIntentActivities(openFileWithIntent, PackageManager.GET_INTENT_FILTERS);
+ queryIntentActivities(openFileWithIntent, PackageManager.GET_RESOLVED_FILTER);
if (launchables != null && launchables.size() > 0) {
try {
diff --git a/src/main/java/com/owncloud/android/ui/helpers/UriUploader.java b/src/main/java/com/owncloud/android/ui/helpers/UriUploader.java
index 7a5ca7e6ab82..2a829eed2a17 100644
--- a/src/main/java/com/owncloud/android/ui/helpers/UriUploader.java
+++ b/src/main/java/com/owncloud/android/ui/helpers/UriUploader.java
@@ -166,7 +166,9 @@ private void requestUpload(String localPath, String remotePath) {
mBehaviour,
null, // MIME type will be detected from file name
false, // do not create parent folder if not existent
- UploadFileOperation.CREATED_BY_USER
+ UploadFileOperation.CREATED_BY_USER,
+ false,
+ false
);
}
diff --git a/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java b/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java
index 081714205987..bd3575348540 100644
--- a/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java
+++ b/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java
@@ -183,7 +183,7 @@ public void onStart() {
}
private void loadAndShowTextPreview() {
- mTextLoadTask = new TextLoadAsyncTask(new WeakReference(mTextPreview));
+ mTextLoadTask = new TextLoadAsyncTask(new WeakReference<>(mTextPreview));
mTextLoadTask.execute(getFile().getStoragePath());
}
@@ -192,14 +192,12 @@ private void loadAndShowTextPreview() {
* Reads the file to preview and shows its contents. Too critical to be anonymous.
*/
private class TextLoadAsyncTask extends AsyncTask {
- private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
private final WeakReference mTextViewReference;
private TextLoadAsyncTask(WeakReference textView) {
mTextViewReference = textView;
}
-
@Override
protected void onPreExecute() {
// not used at the moment
@@ -454,7 +452,7 @@ private void openFile() {
* @return 'True' if the file can be handled by the fragment.
*/
public static boolean canBePreviewed(OCFile file) {
- final List unsupportedTypes = new LinkedList();
+ final List unsupportedTypes = new LinkedList<>();
unsupportedTypes.add("text/richtext");
unsupportedTypes.add("text/rtf");
unsupportedTypes.add("text/vnd.abc");
diff --git a/src/main/java/com/owncloud/android/utils/BitmapUtils.java b/src/main/java/com/owncloud/android/utils/BitmapUtils.java
index 7726cac3991d..0f97f9e0978d 100644
--- a/src/main/java/com/owncloud/android/utils/BitmapUtils.java
+++ b/src/main/java/com/owncloud/android/utils/BitmapUtils.java
@@ -1,4 +1,4 @@
-/**
+/*
* ownCloud Android client application
*
* @author David A. Velasco
@@ -23,7 +23,7 @@
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Matrix;
-import android.media.ExifInterface;
+import android.support.media.ExifInterface;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
@@ -48,7 +48,7 @@ public class BitmapUtils {
* @param srcPath Absolute path to the file containing the image.
* @param reqWidth Width of the surface where the Bitmap will be drawn on, in pixels.
* @param reqHeight Height of the surface where the Bitmap will be drawn on, in pixels.
- * @return
+ * @return decoded bitmap
*/
public static Bitmap decodeSampledBitmapFromFile(String srcPath, int reqWidth, int reqHeight) {
@@ -106,6 +106,23 @@ private static int calculateSampleFactor(Options options, int reqWidth, int reqH
return inSampleSize;
}
+ /**
+ * scales a given bitmap depending on the given size parameters.
+ *
+ * @param bitmap the bitmap to be scaled
+ * @param px the target pixel size
+ * @param width the width
+ * @param height the height
+ * @param max the max(height, width)
+ * @return the scaled bitmap
+ */
+ public static Bitmap scaleBitmap(Bitmap bitmap, float px, int width, int height, int max) {
+ float scale = px / max;
+ int w = Math.round(scale * width);
+ int h = Math.round(scale * height);
+ return Bitmap.createScaledBitmap(bitmap, w, h, true);
+ }
+
/**
* Rotate bitmap according to EXIF orientation.
* Cf. http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/
@@ -172,7 +189,7 @@ else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Lumanance is specified as a percentage in the range 1 - 100.
- * @paran alpha the alpha value between 0 - 1
+ * @param alpha the alpha value between 0 - 1
* adapted from https://svn.codehaus.org/griffon/builders/gfxbuilder/tags/GFXBUILDER_0.2/
* gfxbuilder-core/src/main/com/camick/awt/HSLColor.java
*/
@@ -200,7 +217,7 @@ public static int[] HSLtoRGB(float h, float s, float l, float alpha) {
s /= 100f;
l /= 100f;
- float q = 0;
+ float q;
if (l < 0.5) {
q = l * (1 + s);
diff --git a/src/main/java/com/owncloud/android/utils/DisplayUtils.java b/src/main/java/com/owncloud/android/utils/DisplayUtils.java
index 4b4024ae7ef5..350e4949894e 100644
--- a/src/main/java/com/owncloud/android/utils/DisplayUtils.java
+++ b/src/main/java/com/owncloud/android/utils/DisplayUtils.java
@@ -389,6 +389,11 @@ public static Point getScreenSize(Activity caller) {
public static SpannableStringBuilder createTextWithSpan(String text, String spanText, StyleSpan style) {
SpannableStringBuilder sb = new SpannableStringBuilder(text);
int start = text.lastIndexOf(spanText);
+
+ if (start < 0) {
+ start++;
+ }
+
int end = start + spanText.length();
sb.setSpan(style, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
return sb;
diff --git a/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java
new file mode 100644
index 000000000000..c92635153ec9
--- /dev/null
+++ b/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java
@@ -0,0 +1,329 @@
+/**
+ * Nextcloud Android client application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic
+ * Copyright (C) 2017 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.utils;
+
+import android.accounts.Account;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.MediaStore;
+import android.support.annotation.RequiresApi;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.evernote.android.job.JobRequest;
+import com.owncloud.android.MainApp;
+import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.datamodel.ArbitraryDataProvider;
+import com.owncloud.android.datamodel.FilesystemDataProvider;
+import com.owncloud.android.datamodel.MediaFolderType;
+import com.owncloud.android.datamodel.SyncedFolder;
+import com.owncloud.android.datamodel.SyncedFolderProvider;
+import com.owncloud.android.datamodel.UploadsStorageManager;
+import com.owncloud.android.db.OCUpload;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.jobs.FilesSyncJob;
+import com.owncloud.android.jobs.NContentObserverJob;
+
+import org.lukhnos.nnio.file.FileVisitResult;
+import org.lukhnos.nnio.file.Files;
+import org.lukhnos.nnio.file.Path;
+import org.lukhnos.nnio.file.Paths;
+import org.lukhnos.nnio.file.SimpleFileVisitor;
+import org.lukhnos.nnio.file.attribute.BasicFileAttributes;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/*
+ Various utilities that make auto upload tick
+ */
+public class FilesSyncHelper {
+ public static final String TAG = "FileSyncHelper";
+
+ public static final String GLOBAL = "global";
+ public static final String SYNCEDFOLDERINITIATED = "syncedFolderIntitiated_";
+
+ public static int ContentSyncJobId = 315;
+
+ public static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder) {
+ final Context context = MainApp.getAppContext();
+ final ContentResolver contentResolver = context.getContentResolver();
+ ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);
+
+ Long currentTime = System.currentTimeMillis();
+ double currentTimeInSeconds = currentTime / 1000.0;
+ String currentTimeString = Long.toString((long) currentTimeInSeconds);
+
+ String syncedFolderInitiatedKey = SYNCEDFOLDERINITIATED + syncedFolder.getId();
+ boolean dryRun = TextUtils.isEmpty(arbitraryDataProvider.getValue
+ (GLOBAL, syncedFolderInitiatedKey));
+
+ if (MediaFolderType.IMAGE == syncedFolder.getType()) {
+ if (dryRun) {
+ arbitraryDataProvider.storeOrUpdateKeyValue(GLOBAL, syncedFolderInitiatedKey,
+ currentTimeString);
+ } else {
+ FilesSyncHelper.insertContentIntoDB(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI
+ , syncedFolder);
+ FilesSyncHelper.insertContentIntoDB(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ syncedFolder);
+ }
+
+ } else if (MediaFolderType.VIDEO == syncedFolder.getType()) {
+
+ if (dryRun) {
+ arbitraryDataProvider.storeOrUpdateKeyValue(GLOBAL, syncedFolderInitiatedKey,
+ currentTimeString);
+ } else {
+ FilesSyncHelper.insertContentIntoDB(android.provider.MediaStore.Video.Media.INTERNAL_CONTENT_URI,
+ syncedFolder);
+ FilesSyncHelper.insertContentIntoDB(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ syncedFolder);
+ }
+
+ } else {
+ try {
+
+ if (dryRun) {
+ arbitraryDataProvider.storeOrUpdateKeyValue(GLOBAL, syncedFolderInitiatedKey,
+ currentTimeString);
+ } else {
+ FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
+ Path path = Paths.get(syncedFolder.getLocalPath());
+
+ String dateInitiated = arbitraryDataProvider.getValue(GLOBAL,
+ syncedFolderInitiatedKey);
+
+ Files.walkFileTree(path, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
+
+ File file = path.toFile();
+ if (attrs.lastModifiedTime().toMillis() >= Long.parseLong(dateInitiated) * 1000) {
+ filesystemDataProvider.storeOrUpdateFileValue(path.toAbsolutePath().toString(),
+ attrs.lastModifiedTime().toMillis(), file.isDirectory(), syncedFolder);
+ }
+
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ }
+
+ } catch (IOException e) {
+ Log.e(TAG, "Something went wrong while indexing files for auto upload " + e.getLocalizedMessage());
+ }
+ }
+ }
+
+ public static void insertAllDBEntries(boolean skipCustom) {
+ final Context context = MainApp.getAppContext();
+ final ContentResolver contentResolver = context.getContentResolver();
+ SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver);
+
+ for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
+ if ((syncedFolder.isEnabled()) && ((MediaFolderType.CUSTOM != syncedFolder.getType()) || !skipCustom)) {
+ insertAllDBEntriesForSyncedFolder(syncedFolder);
+ }
+ }
+ }
+
+ private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder) {
+ final Context context = MainApp.getAppContext();
+ final ContentResolver contentResolver = context.getContentResolver();
+ ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);
+
+ Cursor cursor;
+ int column_index_data;
+ int column_index_date_modified;
+
+ final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
+
+ String contentPath;
+ boolean isFolder;
+
+ String[] projection = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DATE_MODIFIED};
+
+ String path = syncedFolder.getLocalPath();
+ if (!path.endsWith("/")) {
+ path = path + "/%";
+ } else {
+ path = path + "%";
+ }
+
+ String syncedFolderInitiatedKey = SYNCEDFOLDERINITIATED + syncedFolder.getId();
+ String dateInitiated = arbitraryDataProvider.getValue(GLOBAL, syncedFolderInitiatedKey);
+
+ cursor = context.getContentResolver().query(uri, projection, MediaStore.MediaColumns.DATA + " LIKE ?",
+ new String[]{path}, null);
+
+ if (cursor != null) {
+ column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+ column_index_date_modified = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED);
+ while (cursor.moveToNext()) {
+ contentPath = cursor.getString(column_index_data);
+ isFolder = new File(contentPath).isDirectory();
+ if (cursor.getLong(column_index_date_modified) >= Long.parseLong(dateInitiated)) {
+ filesystemDataProvider.storeOrUpdateFileValue(contentPath,
+ cursor.getLong(column_index_date_modified), isFolder, syncedFolder);
+ }
+ }
+ cursor.close();
+ }
+ }
+
+ public static void restartJobsIfNeeded() {
+ final Context context = MainApp.getAppContext();
+
+ FileUploader.UploadRequester uploadRequester = new FileUploader.UploadRequester();
+
+ boolean accountExists;
+
+ UploadsStorageManager uploadsStorageManager = new UploadsStorageManager(context.getContentResolver(), context);
+ OCUpload[] failedUploads = uploadsStorageManager.getFailedUploads();
+
+ for (OCUpload failedUpload : failedUploads) {
+ accountExists = false;
+
+ // check if accounts still exists
+ for (Account account : AccountUtils.getAccounts(context)) {
+ if (account.name.equals(failedUpload.getAccountName())) {
+ accountExists = true;
+ break;
+ }
+ }
+
+ if (!accountExists) {
+ uploadsStorageManager.removeUpload(failedUpload);
+ }
+ }
+
+ uploadRequester.retryFailedUploads(
+ context,
+ null,
+ null
+ );
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ public static boolean isContentObserverJobScheduled() {
+ JobScheduler js = MainApp.getAppContext().getSystemService(JobScheduler.class);
+ List jobs = js.getAllPendingJobs();
+
+ if (jobs == null || jobs.size() == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < jobs.size(); i++) {
+ if (jobs.get(i).getId() == ContentSyncJobId) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static void scheduleNJobs(boolean force) {
+ SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().
+ getContentResolver());
+
+
+ boolean hasVideoFolders = false;
+ boolean hasImageFolders = false;
+
+ if (syncedFolderProvider.getSyncedFolders() != null) {
+ for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
+ if (MediaFolderType.VIDEO == syncedFolder.getType()) {
+ hasVideoFolders = true;
+ } else if (MediaFolderType.IMAGE == syncedFolder.getType()) {
+ hasImageFolders = true;
+ }
+ }
+ }
+
+ if (hasImageFolders || hasVideoFolders) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ scheduleJobOnN(hasImageFolders, hasVideoFolders, force);
+ }
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ cancelJobOnN();
+ }
+ }
+ }
+
+ public static void scheduleFilesSyncIfNeeded() {
+ // always run this because it also allows us to perform retries of manual uploads
+ new JobRequest.Builder(FilesSyncJob.TAG)
+ .setPeriodic(900000L, 300000L)
+ .setUpdateCurrent(true)
+ .build()
+ .schedule();
+
+ scheduleNJobs(false);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private static void cancelJobOnN() {
+ JobScheduler jobScheduler = MainApp.getAppContext().getSystemService(JobScheduler.class);
+ if (isContentObserverJobScheduled()) {
+ jobScheduler.cancel(ContentSyncJobId);
+ }
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ private static void scheduleJobOnN(boolean hasImageFolders, boolean hasVideoFolders,
+ boolean force) {
+ JobScheduler jobScheduler = MainApp.getAppContext().getSystemService(JobScheduler.class);
+
+ if ((hasImageFolders || hasVideoFolders) && (!isContentObserverJobScheduled() || force)) {
+ JobInfo.Builder builder = new JobInfo.Builder(ContentSyncJobId, new ComponentName(MainApp.getAppContext(),
+ NContentObserverJob.class.getName()));
+ builder.addTriggerContentUri(new JobInfo.TriggerContentUri(android.provider.MediaStore.
+ Images.Media.INTERNAL_CONTENT_URI,
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
+ builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MediaStore.
+ Images.Media.EXTERNAL_CONTENT_URI,
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
+ builder.addTriggerContentUri(new JobInfo.TriggerContentUri(android.provider.MediaStore.
+ Video.Media.INTERNAL_CONTENT_URI,
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
+ builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MediaStore.
+ Video.Media.EXTERNAL_CONTENT_URI,
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
+ builder.setTriggerContentMaxDelay(1500);
+ jobScheduler.schedule(builder.build());
+ }
+ }
+}
+
diff --git a/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java b/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java
index 8984a639593e..b45b9be79176 100644
--- a/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java
+++ b/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java
@@ -147,7 +147,7 @@ public static Drawable getFolderTypeIcon(boolean isSharedViaUsers, boolean isSha
} else if (isSharedViaUsers) {
drawableId = R.drawable.shared_with_me_folder;
} else {
- drawableId = R.drawable.ic_menu_archive;
+ drawableId = R.drawable.folder;
}
return ThemeUtils.tintDrawable(drawableId, ThemeUtils.primaryColor(account));
@@ -442,7 +442,7 @@ private static void populateMimeTypeIconMapping() {
MIMETYPE_TO_ICON_MAPPING.put("application/yaml", R.drawable.file_code);
MIMETYPE_TO_ICON_MAPPING.put("application/zip", R.drawable.file_zip);
MIMETYPE_TO_ICON_MAPPING.put("database", R.drawable.file);
- MIMETYPE_TO_ICON_MAPPING.put("httpd/unix-directory", R.drawable.ic_menu_archive);
+ MIMETYPE_TO_ICON_MAPPING.put("httpd/unix-directory", R.drawable.folder);
MIMETYPE_TO_ICON_MAPPING.put("image/svg+xml", R.drawable.file_image);
MIMETYPE_TO_ICON_MAPPING.put("image/vector", R.drawable.file_image);
MIMETYPE_TO_ICON_MAPPING.put("text/calendar", R.drawable.file_calendar);
@@ -456,7 +456,7 @@ private static void populateMimeTypeIconMapping() {
MIMETYPE_TO_ICON_MAPPING.put("text/x-python", R.drawable.file_code);
MIMETYPE_TO_ICON_MAPPING.put("text/x-shellscript", R.drawable.file_code);
MIMETYPE_TO_ICON_MAPPING.put("web", R.drawable.file_code);
- MIMETYPE_TO_ICON_MAPPING.put(MimeType.DIRECTORY, R.drawable.ic_menu_archive);
+ MIMETYPE_TO_ICON_MAPPING.put(MimeType.DIRECTORY, R.drawable.folder);
}
/**
diff --git a/src/main/java/com/owncloud/android/utils/ReceiversHelper.java b/src/main/java/com/owncloud/android/utils/ReceiversHelper.java
new file mode 100644
index 000000000000..6ee795064626
--- /dev/null
+++ b/src/main/java/com/owncloud/android/utils/ReceiversHelper.java
@@ -0,0 +1,74 @@
+/**
+ * Nextcloud Android client application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic
+ * Copyright (C) 2017 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.utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import com.evernote.android.job.JobRequest;
+import com.evernote.android.job.util.Device;
+import com.owncloud.android.MainApp;
+
+/*
+ Helper for setting up network and power receivers
+ */
+public class ReceiversHelper {
+
+ public static void registerNetworkChangeReceiver() {
+ Context context = MainApp.getAppContext();
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
+ intentFilter.addAction("android.net.wifi.STATE_CHANGE");
+
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Device.getNetworkType(context).equals(JobRequest.NetworkType.UNMETERED)) {
+ FilesSyncHelper.restartJobsIfNeeded();
+ }
+ }
+ };
+
+ context.registerReceiver(broadcastReceiver, intentFilter);
+ }
+
+ public static void registerPowerChangeReceiver() {
+ Context context = MainApp.getAppContext();
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
+ intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+
+ BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
+ FilesSyncHelper.restartJobsIfNeeded();
+ }
+ }
+ };
+
+ context.registerReceiver(broadcastReceiver, intentFilter);
+ }
+}
diff --git a/src/main/java/com/owncloud/android/utils/ThemeUtils.java b/src/main/java/com/owncloud/android/utils/ThemeUtils.java
index f5ce587e4ee4..e1eef907acee 100644
--- a/src/main/java/com/owncloud/android/utils/ThemeUtils.java
+++ b/src/main/java/com/owncloud/android/utils/ThemeUtils.java
@@ -37,6 +37,7 @@
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.widget.CompoundButtonCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.SwitchCompat;
@@ -254,7 +255,7 @@ public static void colorToolbarProgressBar(FragmentActivity activity, int progre
}
public static void tintCheckbox(AppCompatCheckBox checkBox, int color) {
- checkBox.setSupportButtonTintList(new ColorStateList(
+ CompoundButtonCompat.setButtonTintList(checkBox, new ColorStateList(
new int[][]{
new int[]{-android.R.attr.state_checked},
new int[]{android.R.attr.state_checked},
diff --git a/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java b/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java
index e40252c94452..937b66383b57 100644
--- a/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java
+++ b/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java
@@ -273,7 +273,9 @@ private int getColumnWidthCompatible() {
Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth");
numColumns.setAccessible(true);
return numColumns.getInt(this);
- } catch (NoSuchFieldException | IllegalAccessException e) {
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
diff --git a/src/main/res/drawable-hdpi/common_error.png b/src/main/res/drawable-hdpi/common_error.png
deleted file mode 100644
index 14590e5b1100..000000000000
Binary files a/src/main/res/drawable-hdpi/common_error.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_menu_archive.png b/src/main/res/drawable-hdpi/folder.png
similarity index 100%
rename from src/main/res/drawable-hdpi/ic_menu_archive.png
rename to src/main/res/drawable-hdpi/folder.png
diff --git a/src/main/res/drawable-hdpi/ic_action_cancel_sync.png b/src/main/res/drawable-hdpi/ic_action_cancel_sync.png
deleted file mode 100644
index 491fcbca7492..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_cancel_sync.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_cancel_white.png b/src/main/res/drawable-hdpi/ic_action_cancel_white.png
deleted file mode 100644
index 0754e9faf57f..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_cancel_white.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_copy.png b/src/main/res/drawable-hdpi/ic_action_copy.png
deleted file mode 100644
index 2648a0bd4f1d..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_copy.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_delete_white.png b/src/main/res/drawable-hdpi/ic_action_delete_white.png
deleted file mode 100644
index fc4c01df0f2e..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_delete_white.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_download.png b/src/main/res/drawable-hdpi/ic_action_download.png
deleted file mode 100644
index d85f3e716bfb..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_download.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_move.png b/src/main/res/drawable-hdpi/ic_action_move.png
deleted file mode 100644
index e86a9654395d..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_move.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_set_available_offline.png b/src/main/res/drawable-hdpi/ic_action_set_available_offline.png
deleted file mode 100644
index 3b5149208724..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_set_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_set_available_offline_white.png b/src/main/res/drawable-hdpi/ic_action_set_available_offline_white.png
deleted file mode 100644
index 360c4105b084..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_set_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_share.png b/src/main/res/drawable-hdpi/ic_action_share.png
deleted file mode 100644
index 513199dbbbaf..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_share.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_unset_available_offline.png b/src/main/res/drawable-hdpi/ic_action_unset_available_offline.png
deleted file mode 100644
index ef6229fcc0a2..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_unset_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_action_unset_available_offline_white.png b/src/main/res/drawable-hdpi/ic_action_unset_available_offline_white.png
deleted file mode 100644
index 65c3814250c1..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_action_unset_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_cellphone.png b/src/main/res/drawable-hdpi/ic_cellphone.png
deleted file mode 100644
index aab56fea7077..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_cellphone.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_edit.png b/src/main/res/drawable-hdpi/ic_edit.png
deleted file mode 100644
index 1ca8fa1001ec..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_edit.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_favorite_grey.png b/src/main/res/drawable-hdpi/ic_favorite_grey.png
deleted file mode 100644
index eeac324496db..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_favorite_grey.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_folder_open.png b/src/main/res/drawable-hdpi/ic_folder_open.png
new file mode 100644
index 000000000000..b5e1e0dc66ef
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_folder_open.png differ
diff --git a/src/main/res/drawable-hdpi/ic_folder_star_18dp.png b/src/main/res/drawable-hdpi/ic_folder_star_18dp.png
new file mode 100644
index 000000000000..7161e1d2b934
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_folder_star_18dp.png differ
diff --git a/src/main/res/drawable-hdpi/ic_image_18dp.png b/src/main/res/drawable-hdpi/ic_image_18dp.png
new file mode 100644
index 000000000000..957495d07a7d
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_image_18dp.png differ
diff --git a/src/main/res/drawable-hdpi/ic_information.png b/src/main/res/drawable-hdpi/ic_information.png
deleted file mode 100644
index 92d04d8a0340..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_information.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_key.png b/src/main/res/drawable-hdpi/ic_key.png
deleted file mode 100644
index 73bf0c00e0e8..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_key.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_link_black.png b/src/main/res/drawable-hdpi/ic_link_black.png
deleted file mode 100644
index 76003e2aa387..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_link_black.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_navigate_next.png b/src/main/res/drawable-hdpi/ic_navigate_next.png
deleted file mode 100644
index a4221baf6f48..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_navigate_next.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_open_in_app.png b/src/main/res/drawable-hdpi/ic_open_in_app.png
deleted file mode 100644
index 4eb9993eebac..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_open_in_app.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_open_with.png b/src/main/res/drawable-hdpi/ic_open_with.png
deleted file mode 100644
index 6650711c0090..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_open_with.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_pencil.png b/src/main/res/drawable-hdpi/ic_pencil.png
deleted file mode 100644
index 7c6a745434e3..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_pencil.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_send.png b/src/main/res/drawable-hdpi/ic_send.png
deleted file mode 100644
index c53f0b6b63ca..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_send.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_share.png b/src/main/res/drawable-hdpi/ic_share.png
deleted file mode 100644
index 827e254c95e1..000000000000
Binary files a/src/main/res/drawable-hdpi/ic_share.png and /dev/null differ
diff --git a/src/main/res/drawable-hdpi/ic_video_18dp.png b/src/main/res/drawable-hdpi/ic_video_18dp.png
new file mode 100644
index 000000000000..484034e2798f
Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_video_18dp.png differ
diff --git a/src/main/res/drawable-hdpi/nav_folder_sync.png b/src/main/res/drawable-hdpi/nav_synced_folders.png
similarity index 100%
rename from src/main/res/drawable-hdpi/nav_folder_sync.png
rename to src/main/res/drawable-hdpi/nav_synced_folders.png
diff --git a/src/main/res/drawable-mdpi/common_error.png b/src/main/res/drawable-mdpi/common_error.png
deleted file mode 100644
index ee60165e7284..000000000000
Binary files a/src/main/res/drawable-mdpi/common_error.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_menu_archive.png b/src/main/res/drawable-mdpi/folder.png
similarity index 100%
rename from src/main/res/drawable-mdpi/ic_menu_archive.png
rename to src/main/res/drawable-mdpi/folder.png
diff --git a/src/main/res/drawable-mdpi/ic_action_cancel_sync.png b/src/main/res/drawable-mdpi/ic_action_cancel_sync.png
deleted file mode 100644
index 36eb8eead40b..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_cancel_sync.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_cancel_white.png b/src/main/res/drawable-mdpi/ic_action_cancel_white.png
deleted file mode 100644
index f781daf24c0e..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_cancel_white.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_copy.png b/src/main/res/drawable-mdpi/ic_action_copy.png
deleted file mode 100644
index a5abbb5161b8..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_copy.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_delete_white.png b/src/main/res/drawable-mdpi/ic_action_delete_white.png
deleted file mode 100644
index e21c04e95dd5..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_delete_white.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_download.png b/src/main/res/drawable-mdpi/ic_action_download.png
deleted file mode 100644
index db04fdcdf5bc..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_download.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_move.png b/src/main/res/drawable-mdpi/ic_action_move.png
deleted file mode 100644
index a6bac86c7f5c..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_move.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_refresh_grey.png b/src/main/res/drawable-mdpi/ic_action_refresh_grey.png
deleted file mode 100644
index 3995cd74b957..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_refresh_grey.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_set_available_offline.png b/src/main/res/drawable-mdpi/ic_action_set_available_offline.png
deleted file mode 100644
index 4db968d3b76b..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_set_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_set_available_offline_white.png b/src/main/res/drawable-mdpi/ic_action_set_available_offline_white.png
deleted file mode 100644
index f82d26500e8d..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_set_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_share.png b/src/main/res/drawable-mdpi/ic_action_share.png
deleted file mode 100644
index 7c1deede7c16..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_share.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_unset_available_offline.png b/src/main/res/drawable-mdpi/ic_action_unset_available_offline.png
deleted file mode 100644
index 4facb0c88eff..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_unset_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_action_unset_available_offline_white.png b/src/main/res/drawable-mdpi/ic_action_unset_available_offline_white.png
deleted file mode 100644
index ee0d115bbb27..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_action_unset_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_cellphone.png b/src/main/res/drawable-mdpi/ic_cellphone.png
deleted file mode 100644
index 442bdfe6e854..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_cellphone.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_edit.png b/src/main/res/drawable-mdpi/ic_edit.png
deleted file mode 100644
index 8c7ec3c17cf4..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_edit.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_favorite_grey.png b/src/main/res/drawable-mdpi/ic_favorite_grey.png
deleted file mode 100644
index 46a2f3066bc6..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_favorite_grey.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_folder_open.png b/src/main/res/drawable-mdpi/ic_folder_open.png
new file mode 100644
index 000000000000..0a53eea0dfc6
Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_folder_open.png differ
diff --git a/src/main/res/drawable-mdpi/ic_folder_star_18dp.png b/src/main/res/drawable-mdpi/ic_folder_star_18dp.png
new file mode 100644
index 000000000000..1875a1662f36
Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_folder_star_18dp.png differ
diff --git a/src/main/res/drawable-mdpi/ic_image_18dp.png b/src/main/res/drawable-mdpi/ic_image_18dp.png
new file mode 100644
index 000000000000..eb5683299501
Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_image_18dp.png differ
diff --git a/src/main/res/drawable-mdpi/ic_information.png b/src/main/res/drawable-mdpi/ic_information.png
deleted file mode 100644
index f21c1abc765a..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_information.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_key.png b/src/main/res/drawable-mdpi/ic_key.png
deleted file mode 100644
index dcf345be5d77..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_key.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_link_black.png b/src/main/res/drawable-mdpi/ic_link_black.png
deleted file mode 100644
index 67b2a9eaf226..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_link_black.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_navigate_next.png b/src/main/res/drawable-mdpi/ic_navigate_next.png
deleted file mode 100644
index 3c237ed85f00..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_navigate_next.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_open_in_app.png b/src/main/res/drawable-mdpi/ic_open_in_app.png
deleted file mode 100644
index bf2b7f8689e4..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_open_in_app.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_open_with.png b/src/main/res/drawable-mdpi/ic_open_with.png
deleted file mode 100644
index 128997c0cf9e..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_open_with.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_pencil.png b/src/main/res/drawable-mdpi/ic_pencil.png
deleted file mode 100644
index 7c6a745434e3..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_pencil.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_refresh.png b/src/main/res/drawable-mdpi/ic_refresh.png
deleted file mode 100644
index f37c0781091c..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_refresh.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_send.png b/src/main/res/drawable-mdpi/ic_send.png
deleted file mode 100644
index cfa19a893a08..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_send.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_share.png b/src/main/res/drawable-mdpi/ic_share.png
deleted file mode 100644
index 6ba409b162d6..000000000000
Binary files a/src/main/res/drawable-mdpi/ic_share.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_video_18dp.png b/src/main/res/drawable-mdpi/ic_video_18dp.png
new file mode 100644
index 000000000000..33f88db487ef
Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_video_18dp.png differ
diff --git a/src/main/res/drawable-mdpi/nav_folder_sync.png b/src/main/res/drawable-mdpi/nav_synced_folders.png
similarity index 100%
rename from src/main/res/drawable-mdpi/nav_folder_sync.png
rename to src/main/res/drawable-mdpi/nav_synced_folders.png
diff --git a/src/main/res/drawable-xhdpi/common_error.png b/src/main/res/drawable-xhdpi/common_error.png
deleted file mode 100644
index 08177e7b48d7..000000000000
Binary files a/src/main/res/drawable-xhdpi/common_error.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_menu_archive.png b/src/main/res/drawable-xhdpi/folder.png
similarity index 100%
rename from src/main/res/drawable-xhdpi/ic_menu_archive.png
rename to src/main/res/drawable-xhdpi/folder.png
diff --git a/src/main/res/drawable-xhdpi/ic_action_cancel_sync.png b/src/main/res/drawable-xhdpi/ic_action_cancel_sync.png
deleted file mode 100644
index 031711c0f1ba..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_cancel_sync.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_cancel_white.png b/src/main/res/drawable-xhdpi/ic_action_cancel_white.png
deleted file mode 100644
index 690543be50ac..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_cancel_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_copy.png b/src/main/res/drawable-xhdpi/ic_action_copy.png
deleted file mode 100644
index afd28ddd4a38..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_copy.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_delete_white.png b/src/main/res/drawable-xhdpi/ic_action_delete_white.png
deleted file mode 100644
index 8692fd406c48..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_delete_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_download.png b/src/main/res/drawable-xhdpi/ic_action_download.png
deleted file mode 100644
index b8bd8a6d87d1..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_download.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_move.png b/src/main/res/drawable-xhdpi/ic_action_move.png
deleted file mode 100644
index d231c10e726d..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_move.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_set_available_offline.png b/src/main/res/drawable-xhdpi/ic_action_set_available_offline.png
deleted file mode 100644
index 990dfb82b383..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_set_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_set_available_offline_white.png b/src/main/res/drawable-xhdpi/ic_action_set_available_offline_white.png
deleted file mode 100644
index 17606b3931d5..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_set_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_share.png b/src/main/res/drawable-xhdpi/ic_action_share.png
deleted file mode 100644
index 1cafd21351a1..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_share.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_unset_available_offline.png b/src/main/res/drawable-xhdpi/ic_action_unset_available_offline.png
deleted file mode 100644
index c920e0296ca8..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_unset_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_action_unset_available_offline_white.png b/src/main/res/drawable-xhdpi/ic_action_unset_available_offline_white.png
deleted file mode 100644
index 20df979bd8be..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_action_unset_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_cellphone.png b/src/main/res/drawable-xhdpi/ic_cellphone.png
deleted file mode 100644
index 4a5f0b29cfad..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_cellphone.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_edit.png b/src/main/res/drawable-xhdpi/ic_edit.png
deleted file mode 100644
index 7c6a745434e3..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_edit.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_favorite_grey.png b/src/main/res/drawable-xhdpi/ic_favorite_grey.png
deleted file mode 100644
index 1e9eaa4bd5ab..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_favorite_grey.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_folder_open.png b/src/main/res/drawable-xhdpi/ic_folder_open.png
new file mode 100644
index 000000000000..ad4fcfa2b5a0
Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_folder_open.png differ
diff --git a/src/main/res/drawable-xhdpi/ic_folder_star_18dp.png b/src/main/res/drawable-xhdpi/ic_folder_star_18dp.png
new file mode 100644
index 000000000000..89b75e492d7d
Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_folder_star_18dp.png differ
diff --git a/src/main/res/drawable-xhdpi/ic_image_18dp.png b/src/main/res/drawable-xhdpi/ic_image_18dp.png
new file mode 100644
index 000000000000..fa93aa3c9adc
Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_image_18dp.png differ
diff --git a/src/main/res/drawable-xhdpi/ic_information.png b/src/main/res/drawable-xhdpi/ic_information.png
deleted file mode 100644
index 122c183906ea..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_information.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_key.png b/src/main/res/drawable-xhdpi/ic_key.png
deleted file mode 100644
index 8b44a8181600..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_key.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_link_black.png b/src/main/res/drawable-xhdpi/ic_link_black.png
deleted file mode 100644
index 248782d4a7a4..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_link_black.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_navigate_next.png b/src/main/res/drawable-xhdpi/ic_navigate_next.png
deleted file mode 100644
index 8eab33c63056..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_navigate_next.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_open_in_app.png b/src/main/res/drawable-xhdpi/ic_open_in_app.png
deleted file mode 100644
index bf2b7f8689e4..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_open_in_app.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_open_with.png b/src/main/res/drawable-xhdpi/ic_open_with.png
deleted file mode 100644
index bf2b7f8689e4..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_open_with.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_pencil.png b/src/main/res/drawable-xhdpi/ic_pencil.png
deleted file mode 100644
index 7c6a745434e3..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_pencil.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_refresh.png b/src/main/res/drawable-xhdpi/ic_refresh.png
deleted file mode 100644
index 63f616dc29a3..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_refresh.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_send.png b/src/main/res/drawable-xhdpi/ic_send.png
deleted file mode 100644
index cd2590b7b5c2..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_send.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_share.png b/src/main/res/drawable-xhdpi/ic_share.png
deleted file mode 100644
index 1cafd21351a1..000000000000
Binary files a/src/main/res/drawable-xhdpi/ic_share.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_video_18dp.png b/src/main/res/drawable-xhdpi/ic_video_18dp.png
new file mode 100644
index 000000000000..557c6a7cd266
Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_video_18dp.png differ
diff --git a/src/main/res/drawable-xhdpi/nav_folder_sync.png b/src/main/res/drawable-xhdpi/nav_synced_folders.png
similarity index 100%
rename from src/main/res/drawable-xhdpi/nav_folder_sync.png
rename to src/main/res/drawable-xhdpi/nav_synced_folders.png
diff --git a/src/main/res/drawable-xxhdpi/common_error.png b/src/main/res/drawable-xxhdpi/common_error.png
deleted file mode 100644
index dc007ee65fa5..000000000000
Binary files a/src/main/res/drawable-xxhdpi/common_error.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_menu_archive.png b/src/main/res/drawable-xxhdpi/folder.png
similarity index 100%
rename from src/main/res/drawable-xxhdpi/ic_menu_archive.png
rename to src/main/res/drawable-xxhdpi/folder.png
diff --git a/src/main/res/drawable-xxhdpi/ic_action_cancel_sync.png b/src/main/res/drawable-xxhdpi/ic_action_cancel_sync.png
deleted file mode 100644
index 84a327a8fd4d..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_cancel_sync.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_cancel_white.png b/src/main/res/drawable-xxhdpi/ic_action_cancel_white.png
deleted file mode 100644
index f06f53d969e5..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_cancel_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_copy.png b/src/main/res/drawable-xxhdpi/ic_action_copy.png
deleted file mode 100644
index c170a270d0c9..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_copy.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_delete_white.png b/src/main/res/drawable-xxhdpi/ic_action_delete_white.png
deleted file mode 100644
index 3e6a6ac5591f..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_delete_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_download.png b/src/main/res/drawable-xxhdpi/ic_action_download.png
deleted file mode 100644
index 382a7ec896bf..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_download.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_move.png b/src/main/res/drawable-xxhdpi/ic_action_move.png
deleted file mode 100644
index 13ab75510c82..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_move.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_set_available_offline.png b/src/main/res/drawable-xxhdpi/ic_action_set_available_offline.png
deleted file mode 100644
index 95502de3f1c9..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_set_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_set_available_offline_white.png b/src/main/res/drawable-xxhdpi/ic_action_set_available_offline_white.png
deleted file mode 100644
index 75f1922678b4..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_set_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_share.png b/src/main/res/drawable-xxhdpi/ic_action_share.png
deleted file mode 100644
index 0c460c479db4..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_share.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_unset_available_offline.png b/src/main/res/drawable-xxhdpi/ic_action_unset_available_offline.png
deleted file mode 100644
index 4aea83a9ec5f..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_unset_available_offline.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_action_unset_available_offline_white.png b/src/main/res/drawable-xxhdpi/ic_action_unset_available_offline_white.png
deleted file mode 100644
index f6ebd03db120..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_action_unset_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_cellphone.png b/src/main/res/drawable-xxhdpi/ic_cellphone.png
deleted file mode 100644
index 393e0e3fa5da..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_cellphone.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_edit.png b/src/main/res/drawable-xxhdpi/ic_edit.png
deleted file mode 100644
index 2beb2b4279e7..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_edit.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_favorite_grey.png b/src/main/res/drawable-xxhdpi/ic_favorite_grey.png
deleted file mode 100644
index 26a843ba57e5..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_favorite_grey.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_folder_open.png b/src/main/res/drawable-xxhdpi/ic_folder_open.png
new file mode 100644
index 000000000000..bc826f4ab947
Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_folder_open.png differ
diff --git a/src/main/res/drawable-xxhdpi/ic_folder_star_18dp.png b/src/main/res/drawable-xxhdpi/ic_folder_star_18dp.png
new file mode 100644
index 000000000000..6662bf1572af
Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_folder_star_18dp.png differ
diff --git a/src/main/res/drawable-xxhdpi/ic_image_18dp.png b/src/main/res/drawable-xxhdpi/ic_image_18dp.png
new file mode 100644
index 000000000000..b3e3c2ffffdd
Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_image_18dp.png differ
diff --git a/src/main/res/drawable-xxhdpi/ic_information.png b/src/main/res/drawable-xxhdpi/ic_information.png
deleted file mode 100644
index e0056bb7fc2d..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_information.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_key.png b/src/main/res/drawable-xxhdpi/ic_key.png
deleted file mode 100644
index 27f889e984cd..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_key.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_link_black.png b/src/main/res/drawable-xxhdpi/ic_link_black.png
deleted file mode 100644
index af03b8558fde..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_link_black.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_navigate_next.png b/src/main/res/drawable-xxhdpi/ic_navigate_next.png
deleted file mode 100644
index d4b141b9da40..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_navigate_next.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_open_with.png b/src/main/res/drawable-xxhdpi/ic_open_with.png
deleted file mode 100644
index 455423da7a03..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_open_with.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_pencil.png b/src/main/res/drawable-xxhdpi/ic_pencil.png
deleted file mode 100644
index 2beb2b4279e7..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_pencil.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_refresh.png b/src/main/res/drawable-xxhdpi/ic_refresh.png
deleted file mode 100644
index 07a6372dfe82..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_refresh.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_send.png b/src/main/res/drawable-xxhdpi/ic_send.png
deleted file mode 100644
index 55f6ddb7737e..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_send.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_share.png b/src/main/res/drawable-xxhdpi/ic_share.png
deleted file mode 100644
index 0c460c479db4..000000000000
Binary files a/src/main/res/drawable-xxhdpi/ic_share.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_video_18dp.png b/src/main/res/drawable-xxhdpi/ic_video_18dp.png
new file mode 100644
index 000000000000..cf610376dbae
Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_video_18dp.png differ
diff --git a/src/main/res/drawable-xxhdpi/nav_folder_sync.png b/src/main/res/drawable-xxhdpi/nav_synced_folders.png
similarity index 100%
rename from src/main/res/drawable-xxhdpi/nav_folder_sync.png
rename to src/main/res/drawable-xxhdpi/nav_synced_folders.png
diff --git a/src/main/res/drawable-xxhdpi/owncloud_progress_bg_light.9.png b/src/main/res/drawable-xxhdpi/owncloud_progress_bg_light.9.png
deleted file mode 100644
index fb146c33987e..000000000000
Binary files a/src/main/res/drawable-xxhdpi/owncloud_progress_bg_light.9.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/owncloud_progress_primary_light.9.png b/src/main/res/drawable-xxhdpi/owncloud_progress_primary_light.9.png
deleted file mode 100644
index 1fc3b4ec7c98..000000000000
Binary files a/src/main/res/drawable-xxhdpi/owncloud_progress_primary_light.9.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/owncloud_progress_secondary_light.9.png b/src/main/res/drawable-xxhdpi/owncloud_progress_secondary_light.9.png
deleted file mode 100644
index 6cae209f42bc..000000000000
Binary files a/src/main/res/drawable-xxhdpi/owncloud_progress_secondary_light.9.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_action_cancel_sync.png b/src/main/res/drawable-xxxhdpi/ic_action_cancel_sync.png
deleted file mode 100644
index 6db45391d787..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_action_cancel_sync.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_action_delete_white.png b/src/main/res/drawable-xxxhdpi/ic_action_delete_white.png
deleted file mode 100644
index 99330656f093..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_action_delete_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_action_download.png b/src/main/res/drawable-xxxhdpi/ic_action_download.png
deleted file mode 100644
index 4404433b4756..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_action_download.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_action_set_available_offline_white.png b/src/main/res/drawable-xxxhdpi/ic_action_set_available_offline_white.png
deleted file mode 100644
index 23c4b1004b47..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_action_set_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_action_unset_available_offline_white.png b/src/main/res/drawable-xxxhdpi/ic_action_unset_available_offline_white.png
deleted file mode 100644
index df89de764099..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_action_unset_available_offline_white.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_cellphone.png b/src/main/res/drawable-xxxhdpi/ic_cellphone.png
deleted file mode 100644
index ebb939ffe1e2..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_cellphone.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_edit.png b/src/main/res/drawable-xxxhdpi/ic_edit.png
deleted file mode 100644
index 0a20a6076541..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_edit.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_favorite_grey.png b/src/main/res/drawable-xxxhdpi/ic_favorite_grey.png
deleted file mode 100644
index 800daea16723..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_favorite_grey.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_folder_star_18dp.png b/src/main/res/drawable-xxxhdpi/ic_folder_star_18dp.png
new file mode 100644
index 000000000000..fbeb81a7ec19
Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_folder_star_18dp.png differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_image_18dp.png b/src/main/res/drawable-xxxhdpi/ic_image_18dp.png
new file mode 100644
index 000000000000..07f0dfdf5f0b
Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_image_18dp.png differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_information.png b/src/main/res/drawable-xxxhdpi/ic_information.png
deleted file mode 100644
index 2f932ef8540d..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_information.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_link_black.png b/src/main/res/drawable-xxxhdpi/ic_link_black.png
deleted file mode 100644
index 377cf9ab52ed..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_link_black.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_navigate_next.png b/src/main/res/drawable-xxxhdpi/ic_navigate_next.png
deleted file mode 100644
index 12ec7bf0ab9e..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_navigate_next.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_open_in_app.png b/src/main/res/drawable-xxxhdpi/ic_open_in_app.png
deleted file mode 100644
index 87a63fe252c0..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_open_in_app.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_open_with.png b/src/main/res/drawable-xxxhdpi/ic_open_with.png
deleted file mode 100644
index 87a63fe252c0..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_open_with.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_refresh.png b/src/main/res/drawable-xxxhdpi/ic_refresh.png
deleted file mode 100644
index c1ea1e23d0cd..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_refresh.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_send.png b/src/main/res/drawable-xxxhdpi/ic_send.png
deleted file mode 100644
index c7362e87bcf9..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_send.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_share.png b/src/main/res/drawable-xxxhdpi/ic_share.png
deleted file mode 100644
index e275d938448c..000000000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_share.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_video_18dp.png b/src/main/res/drawable-xxxhdpi/ic_video_18dp.png
new file mode 100644
index 000000000000..5b3a9e8e4155
Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_video_18dp.png differ
diff --git a/src/main/res/drawable-xxxhdpi/nav_folder_sync.png b/src/main/res/drawable-xxxhdpi/nav_synced_folders.png
similarity index 100%
rename from src/main/res/drawable-xxxhdpi/nav_folder_sync.png
rename to src/main/res/drawable-xxxhdpi/nav_synced_folders.png
diff --git a/src/main/res/drawable/borderless_btn.xml b/src/main/res/drawable/borderless_btn.xml
new file mode 100644
index 000000000000..6cc185ea0f57
--- /dev/null
+++ b/src/main/res/drawable/borderless_btn.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/drawable/favorite_button_selector.xml b/src/main/res/drawable/favorite_button_selector.xml
deleted file mode 100644
index 3868e80cca5f..000000000000
--- a/src/main/res/drawable/favorite_button_selector.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/res/layout-land/account_setup.xml b/src/main/res/layout-land/account_setup.xml
index 3243dea13d56..224556826651 100644
--- a/src/main/res/layout-land/account_setup.xml
+++ b/src/main/res/layout-land/account_setup.xml
@@ -145,6 +145,7 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/alternate_half_margin"
android:drawableLeft="@android:drawable/stat_notify_sync"
+ android:drawableStart="@android:drawable/stat_notify_sync"
android:drawablePadding="@dimen/alternate_half_padding"
android:gravity="center_vertical"
android:textColor="@color/login_text_color"
@@ -220,8 +221,7 @@
android:hint="@string/auth_username"
android:inputType="textNoSuggestions"
android:textColor="@color/login_text_color"
- android:textColorHint="@color/login_text_hint_color"
- android:contentDescription="@string/auth_username"/>
+ android:textColorHint="@color/login_text_hint_color"/>
@@ -253,6 +253,7 @@
android:gravity="center_vertical"
android:text="@string/auth_unauthorized"
android:drawableLeft="@android:drawable/stat_notify_sync"
+ android:drawableStart="@android:drawable/stat_notify_sync"
android:drawablePadding="@dimen/alternate_half_padding"
android:textColor="@color/login_text_color"
android:contentDescription="@string/auth_unauthorized"
diff --git a/src/main/res/layout/account_action.xml b/src/main/res/layout/account_action.xml
index 0bdecc04a645..cb32971336f1 100644
--- a/src/main/res/layout/account_action.xml
+++ b/src/main/res/layout/account_action.xml
@@ -32,17 +32,20 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/list_item_avatar_icon_margin"
- android:src="@drawable/ic_account_plus"/>
+ android:layout_marginStart="@dimen/list_item_avatar_text_margin"
+ android:src="@drawable/ic_account_plus"
+ android:contentDescription="@string/prefs_add_account"/>
diff --git a/src/main/res/layout/account_item.xml b/src/main/res/layout/account_item.xml
index 8b92fe0119a2..5424e5f4cc4e 100644
--- a/src/main/res/layout/account_item.xml
+++ b/src/main/res/layout/account_item.xml
@@ -43,7 +43,8 @@
android:layout_marginLeft="12dp"
android:layout_marginRight="1dp"
android:layout_marginTop="1dp"
- android:src="@drawable/ic_menu_archive"/>
+ android:src="@drawable/folder"
+ android:contentDescription="@string/avatar"/>
+ android:src="@drawable/ic_account_circle_white_18dp"
+ android:contentDescription="@string/active_user"/>
+ android:text="@string/placeholder_filename"/>
\ No newline at end of file
diff --git a/src/main/res/layout/activity_row.xml b/src/main/res/layout/activity_row.xml
index f25e5a0bddd0..ea8eabf03586 100644
--- a/src/main/res/layout/activity_row.xml
+++ b/src/main/res/layout/activity_row.xml
@@ -50,7 +50,7 @@
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
android:duplicateParentState="true"
- android:maxLines="1"
+ android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
diff --git a/src/main/res/layout/contactlist_fragment.xml b/src/main/res/layout/contactlist_fragment.xml
index 22e10e931c34..2e9449d20a09 100644
--- a/src/main/res/layout/contactlist_fragment.xml
+++ b/src/main/res/layout/contactlist_fragment.xml
@@ -46,7 +46,8 @@
+ android:src="@drawable/uploader_list_separator"
+ android:contentDescription="@null"/>
\ No newline at end of file
diff --git a/src/main/res/layout/drawer_header.xml b/src/main/res/layout/drawer_header.xml
index 1592e67ba4fe..95b7f5e447c2 100644
--- a/src/main/res/layout/drawer_header.xml
+++ b/src/main/res/layout/drawer_header.xml
@@ -72,7 +72,7 @@
>
diff --git a/src/main/res/layout/file_details_fragment.xml b/src/main/res/layout/file_details_fragment.xml
index cffe9ae5d6e7..ca6c9611a3ec 100644
--- a/src/main/res/layout/file_details_fragment.xml
+++ b/src/main/res/layout/file_details_fragment.xml
@@ -167,7 +167,10 @@
android:layout_height="wrap_content"
android:layout_gravity="start"
android:text="@string/favorite"
- android:textSize="16sp"/>
+ android:textSize="16sp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"/>
+ android:src="@drawable/ic_cancel"
+ android:contentDescription="@string/common_cancel"/>
diff --git a/src/main/res/layout/file_details_share_user_item.xml b/src/main/res/layout/file_details_share_user_item.xml
index 9c7fed9ca2d4..16f59de85554 100644
--- a/src/main/res/layout/file_details_share_user_item.xml
+++ b/src/main/res/layout/file_details_share_user_item.xml
@@ -35,7 +35,7 @@
android:text="@string/username"
android:id="@+id/userOrGroupName"
android:layout_margin="12dp"
- android:maxLines="1"
+ android:singleLine="true"
android:ellipsize="middle"
android:textColor="@color/black"/>
diff --git a/src/main/res/layout/file_download_fragment.xml b/src/main/res/layout/file_download_fragment.xml
index 28d1846ddad1..9d5fc86c6155 100644
--- a/src/main/res/layout/file_download_fragment.xml
+++ b/src/main/res/layout/file_download_fragment.xml
@@ -42,27 +42,25 @@
android:gravity="center"
android:layout_marginTop="@dimen/fragment_margin"
android:layout_marginBottom="@dimen/alternate_fragment_margin"
- android:orientation="horizontal"
- >
+ android:orientation="horizontal">
+ android:indeterminateOnly="false"/>
+ android:contentDescription="@string/common_cancel"/>
diff --git a/src/main/res/layout/files.xml b/src/main/res/layout/files.xml
index 197d14390e41..7af8dfc98115 100644
--- a/src/main/res/layout/files.xml
+++ b/src/main/res/layout/files.xml
@@ -34,7 +34,6 @@
layout="@layout/toolbar_standard" />
@@ -38,7 +38,8 @@
+ android:src="@drawable/uploader_list_separator"
+ android:contentDescription="@null"/>
diff --git a/src/main/res/layout/folder_sync_item_header.xml b/src/main/res/layout/folder_sync_item_header.xml
deleted file mode 100644
index a72bdc03fc05..000000000000
--- a/src/main/res/layout/folder_sync_item_header.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/res/layout/grid_image.xml b/src/main/res/layout/grid_image.xml
index 6c13b9962c71..3e58eb56be10 100644
--- a/src/main/res/layout/grid_image.xml
+++ b/src/main/res/layout/grid_image.xml
@@ -36,7 +36,7 @@
android:paddingLeft="@dimen/alternate_padding"
android:paddingRight="@dimen/alternate_padding"
android:scaleType="centerCrop"
- android:src="@drawable/ic_menu_archive"/>
+ android:src="@drawable/folder"/>
-
+
-
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"
+ android:src="@drawable/folder"/>
-
+
-
+
-
-
-
-
-
-
-
+ android:text="@string/synced_folders_plus"
+ android:textColor="#ffffff"
+ android:textSize="22sp"
+ android:textStyle="bold"/>
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/list_item.xml b/src/main/res/layout/list_item.xml
index 43d3f897d3c2..d1322222b2bd 100644
--- a/src/main/res/layout/list_item.xml
+++ b/src/main/res/layout/list_item.xml
@@ -44,7 +44,7 @@
android:layout_height="@dimen/file_icon_size"
android:layout_centerInParent="true"
android:layout_marginLeft="8dp"
- android:src="@drawable/ic_menu_archive" />
+ android:src="@drawable/folder" />
@@ -110,7 +110,7 @@
android:id="@+id/file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Size MB"
+ android:text="@string/placeholder_filesize"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size"/>
@@ -118,8 +118,9 @@
android:id="@+id/file_separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingRight="@dimen/standard_quarter_padding"
android:gravity="right"
- android:text=", "
+ android:text="@string/info_separator"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size"/>
@@ -128,7 +129,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
- android:text="Mod Date"
+ android:text="@string/placeholder_media_time"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size"/>
diff --git a/src/main/res/layout/listrow_details.xml b/src/main/res/layout/listrow_details.xml
deleted file mode 100644
index 46e371ebabea..000000000000
--- a/src/main/res/layout/listrow_details.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/res/layout/listrow_group.xml b/src/main/res/layout/listrow_group.xml
deleted file mode 100644
index ccea6301cd7d..000000000000
--- a/src/main/res/layout/listrow_group.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/src/main/res/layout/log_item.xml b/src/main/res/layout/log_item.xml
deleted file mode 100644
index e1083aefda53..000000000000
--- a/src/main/res/layout/log_item.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/res/layout/notification_with_progress_bar.xml b/src/main/res/layout/notification_with_progress_bar.xml
index 7d7dd8383db0..79588e6e8961 100644
--- a/src/main/res/layout/notification_with_progress_bar.xml
+++ b/src/main/res/layout/notification_with_progress_bar.xml
@@ -36,7 +36,7 @@
diff --git a/src/main/res/layout/share_user_item.xml b/src/main/res/layout/share_user_item.xml
index 5c579f6c19bb..e2eaa866a92e 100644
--- a/src/main/res/layout/share_user_item.xml
+++ b/src/main/res/layout/share_user_item.xml
@@ -34,7 +34,7 @@
android:layout_gravity="center_vertical"/>
@@ -54,7 +55,8 @@
android:id="@+id/unshareButton"
android:src="@drawable/ic_action_delete_grey"
android:layout_gravity="center_vertical"
- android:padding="@dimen/standard_half_padding"/>
+ android:padding="@dimen/standard_half_padding"
+ android:contentDescription="@string/common_delete"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/folder_sync_layout.xml b/src/main/res/layout/synced_folders_layout.xml
similarity index 50%
rename from src/main/res/layout/folder_sync_layout.xml
rename to src/main/res/layout/synced_folders_layout.xml
index 94fb76abaa43..e7d6c75c6b31 100644
--- a/src/main/res/layout/folder_sync_layout.xml
+++ b/src/main/res/layout/synced_folders_layout.xml
@@ -2,8 +2,8 @@
-
+ android:fitsSystemWindows="true"
+ tools:openDrawer="start">
-
-
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+ android:orientation="vertical"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
@@ -75,7 +108,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="@dimen/standard_half_margin"
- android:text="@string/folder_sync_loading_folders"
+ android:text="@string/synced_folders_loading_folders"
android:textSize="26sp"/>
@@ -86,9 +119,21 @@
android:layout_gravity="center"
android:layout_margin="@dimen/standard_margin"
android:gravity="center"
- android:text="@string/folder_sync_no_results"
- android:visibility="gone" />
-
+ android:text="@string/synced_folders_no_results"
+ android:visibility="gone"/>
+
+
+
-
+
diff --git a/src/main/res/layout/folder_sync_settings_layout.xml b/src/main/res/layout/synced_folders_settings_layout.xml
similarity index 65%
rename from src/main/res/layout/folder_sync_settings_layout.xml
rename to src/main/res/layout/synced_folders_settings_layout.xml
index a709bcef1dbd..133c70fa407d 100644
--- a/src/main/res/layout/folder_sync_settings_layout.xml
+++ b/src/main/res/layout/synced_folders_settings_layout.xml
@@ -18,8 +18,8 @@
You should have received a copy of the GNU Affero General Public
License along with this program. If not, see .
-->
-
+ android:paddingTop="@dimen/standard_padding">
@@ -62,8 +61,8 @@
android:layout_height="match_parent"
android:gravity="end|top"
android:orientation="vertical"
- android:paddingTop="@dimen/standard_padding"
- android:paddingLeft="@dimen/standard_padding">
+ android:paddingLeft="@dimen/standard_padding"
+ android:paddingTop="@dimen/standard_padding">
+ android:minHeight="?attr/listPreferredItemHeightSmall">
-
+ android:layout_weight="1"
+ android:paddingBottom="@dimen/standard_padding"
+ android:paddingTop="@dimen/standard_padding">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_weight="1"
+ android:paddingBottom="@dimen/standard_padding"
+ android:paddingTop="@dimen/standard_padding">
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -139,7 +224,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
- android:maxLines="1"
+ android:singleLine="true"
android:text="@string/auto_upload_on_wifi"
android:textAppearance="?attr/textAppearanceListItem"/>
@@ -186,7 +271,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
- android:maxLines="1"
+ android:singleLine="true"
android:text="@string/instant_upload_on_charging"
android:textAppearance="?attr/textAppearanceListItem"/>
@@ -233,7 +318,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
- android:maxLines="1"
+ android:singleLine="true"
android:text="@string/prefs_instant_upload_path_use_subfolders_title"
android:textAppearance="?attr/textAppearanceListItem"/>
@@ -288,7 +373,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
- android:maxLines="1"
+ android:singleLine="true"
android:text="@string/prefs_instant_behaviour_title"
android:textAppearance="?attr/textAppearanceListItem"/>
@@ -307,25 +392,39 @@
-
+ android:layout_height="wrap_content">
+ android:layout_alignParentLeft="true"
+ android:text="@string/common_delete"/>
-
+ android:layout_alignParentRight="true">
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/upload_files_layout.xml b/src/main/res/layout/upload_files_layout.xml
index b0b32982cf36..fb74bc9b7ddb 100644
--- a/src/main/res/layout/upload_files_layout.xml
+++ b/src/main/res/layout/upload_files_layout.xml
@@ -45,11 +45,12 @@
@@ -73,9 +74,7 @@
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
- android:paddingLeft="@dimen/standard_padding"
- android:paddingRight="@dimen/standard_padding"
- android:paddingBottom="@dimen/standard_padding">
+ android:padding="@dimen/standard_padding">
+ android:src="@drawable/folder" />
@@ -37,7 +37,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="middle"
- android:maxLines="1"
+ android:singleLine="true"
android:textColor="@color/textColor"
android:text="@string/placeholder_filename"
android:textSize="@dimen/two_line_primary_text_size" />
@@ -53,7 +53,7 @@
android:gravity="left"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:ellipsize="middle"
- android:maxLines="1"
+ android:singleLine="true"
android:text="@string/placeholder_filesize"
android:textSize="@dimen/upload_list_item_text_size"/>
diff --git a/src/main/res/layout/uploader_list_item_layout.xml b/src/main/res/layout/uploader_list_item_layout.xml
index 43c68211835e..4a07d82c3b52 100644
--- a/src/main/res/layout/uploader_list_item_layout.xml
+++ b/src/main/res/layout/uploader_list_item_layout.xml
@@ -29,7 +29,7 @@
android:layout_height="@dimen/file_icon_size"
android:layout_gravity="center_vertical"
android:layout_margin="@dimen/uploader_list_item_layout_image_margin"
- android:src="@drawable/ic_menu_archive" />
+ android:src="@drawable/folder" />
@@ -62,7 +62,7 @@
android:id="@+id/file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Size MB"
+ android:text="@string/placeholder_filesize"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size"/>
@@ -70,8 +70,9 @@
android:id="@+id/file_separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingRight="@dimen/standard_quarter_padding"
android:gravity="right"
- android:text=", "
+ android:text="@string/info_separator"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size"/>
@@ -80,7 +81,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
- android:text="Mod Date"
+ android:text="@string/placeholder_media_time"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size"/>
diff --git a/src/main/res/menu/drawer_menu.xml b/src/main/res/menu/drawer_menu.xml
index 764a14a4d9c1..b84563e4792c 100644
--- a/src/main/res/menu/drawer_menu.xml
+++ b/src/main/res/menu/drawer_menu.xml
@@ -80,9 +80,9 @@
android:title="@string/drawer_item_notifications"/>
+ android:id="@+id/nav_synced_folders"
+ android:icon="@drawable/nav_synced_folders"
+ android:title="@string/drawer_synced_folders"/>
@@ -141,7 +127,6 @@
diff --git a/src/main/res/menu/upload_list_menu.xml b/src/main/res/menu/upload_list_menu.xml
index d656e327e338..f20d91f27619 100755
--- a/src/main/res/menu/upload_list_menu.xml
+++ b/src/main/res/menu/upload_list_menu.xml
@@ -17,18 +17,31 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
-->
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml
index df339bfda29a..1e3a804f1319 100644
--- a/src/main/res/values-ar/strings.xml
+++ b/src/main/res/values-ar/strings.xml
@@ -262,8 +262,6 @@
نعتذر عن ذلك !
معاينة الصورة
%1$s تعذر نسخه %2$s للمجلد المحلي
- المجلد المحلي
- مجلد عن بعد
حدث خطأ ما أثناء محاولة مشاركة هذا الملف أو المجلد
حدث خطأ ما أثناء محاولة إلغاء مشاركة هذا الملف أو المجلد
إدخِل كلمة السر
@@ -340,10 +338,8 @@
هل ترغب فعلاً في حذف العناصر المحددة ؟
بحث
تعلم المزيد
- رفع تلقائي
شارك معنا
ساهم بفعالية
- الإعدادات
لا توجد هناك إخطارات
اسم الملف
نوع الملف
@@ -385,7 +381,5 @@
الخصوصية
المجلد غير موجود !
- تهيئة المجلدات
-
أفحص أتصال الخادم
diff --git a/src/main/res/values-ast/strings.xml b/src/main/res/values-ast/strings.xml
index 241219c9c8fc..0e6da2ef3c9f 100644
--- a/src/main/res/values-ast/strings.xml
+++ b/src/main/res/values-ast/strings.xml
@@ -310,8 +310,8 @@
Nun se pudo copiar %1$s al ficheru llocal %2$s
Carpeta de xuba nel intre
- Carpeta llocal
- Carpeta remota
+ Carpeta llocal
+ Carpeta remota
Usar socarpetes
Nun pue compartise. Por favor, comprueba si\'l ficheru esiste
Hebo un fallu mientres s\'intentaba compartir esti ficheru o carpeta
@@ -468,10 +468,10 @@
Mover a…
Copiar a…
Escoyer carpeta…
- Cargando carpetes…
- Nun s\'alcontraron carpetes de medios.
- Preferencies pa la xuba automática
- Axustes
+ Cargando carpetes…
+ Nun s\'alcontraron carpetes de medios.
+ Preferencies pa la xuba automática
+ Axustes
Cargando actividaes…
Nun s\'alcontraron actividaes.
diff --git a/src/main/res/values-bg-rBG/strings.xml b/src/main/res/values-bg-rBG/strings.xml
index 1734266efa27..f860d2b65086 100644
--- a/src/main/res/values-bg-rBG/strings.xml
+++ b/src/main/res/values-bg-rBG/strings.xml
@@ -281,8 +281,8 @@
Преглед на изображението
%1$s не може да бъде копиран в локалната папка %2$s
Папка за незабавно качените
- Локална папка
- Отдалечена папка
+ Локална папка
+ Отдалечена папка
Ползване на подпапки
Съхраняване в подпапки, разделени по година и месец
@@ -416,18 +416,18 @@
Търсене
Това е функционалност на Nextcloud, моля актуализирайте.
Научете повече
- Автоматично качване
+ Автоматично качване
Участвайте
Помогни с тестването
Интересувате ли се да ни помогнете с тестването на следващата версия?
Преместване в…
Копиране в…
Избери папка…
- Зареждане на папки…
- Не са открити медийни папки.
- Предпочитания за автоматично качване
- Настройки
- За %1$s
+ Зареждане на папки…
+ Не са открити медийни папки.
+ Предпочитания за автоматично качване
+ Настройки
+ За %1$s
- %d избран
- %d избрани
diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml
index a193904dc0e0..c346840aadd6 100644
--- a/src/main/res/values-ca/strings.xml
+++ b/src/main/res/values-ca/strings.xml
@@ -275,8 +275,8 @@
Visualització prèvia d\'imatge
%1$s no s\'ha pogut copiar a la carpeta local %2$s
Carpeta de pujada instantània
- Carpeta local
- Carpeta remota
+ Carpeta local
+ Carpeta remota
Feu servir subcarpetes
Desar a subcarpetes ordenades per any i mes
@@ -415,17 +415,19 @@
Cerca
És una característica de Nextcloud. Siusplau actualitzeu.
Més informació
- Pujada automàtica
+ Pujada automàtica
Participa
Versió candidata
Contribuïu activament
Mou a…
Copia a…
Tria carpeta…
- Carregant carpetes…
- No s\'han trobat carpetes amb elements multimèdia.
- Configuració
- Per %1$s
+ Carregant carpetes…
+ No s\'han trobat carpetes amb elements multimèdia.
+ Preferències de la pujada automàtica
+ Configuració
+ La pujada instantània s\'ha renovat completament. Mireu el menú principal i torneu a configurar l\'auto pujada. Disculpeu les molèsties.\n\nGaudiu de les noves i ampliades capacitats de l\'auto pujada!
+ Per %1$s
- %d seleccionat
- %d seleccionats
diff --git a/src/main/res/values-cs-rCZ/strings.xml b/src/main/res/values-cs-rCZ/strings.xml
index 9871c1e1e38a..68c1a1e63064 100644
--- a/src/main/res/values-cs-rCZ/strings.xml
+++ b/src/main/res/values-cs-rCZ/strings.xml
@@ -362,8 +362,8 @@
%1$s nelze zkopírovat do místního adresáře %2$s
Adresář pro okamžité nahrání
- Místní adresář
- Vzdálený adresář
+ Místní adresář
+ Vzdálený adresář
Používat podadresáře
Ukládat v podadresářích podle roku a měsíce
@@ -557,7 +557,7 @@
Hledat
Toto je Nextcloud funkce, prosím nahrát
Více
- Automatické nahrávání
+ Automatické nahrávání
Zúčastnit se
Pomoz nám testovat
Našli jste chybu? Něco podivného?
@@ -577,12 +577,12 @@
Přesunout do…
Kopírovat do…
Vybrat adresář…
- Načítání adresářů…
- Nebyly nalezeny žádné adresáře médií.
- Nastavení automatického nahrávání
- Nastavení
- Okamžité nahrávání dat bylo kompletně předěláno. Navštivte hlavní menu a nakonfigurujte automatické nahrávání svých dat. Omlouváme se za nepříjemnosti.\n\nUžívejte si nové a rozšířené možnosti nahrávání dat!
- Pro %1$s
+ Načítání adresářů…
+ Nebyly nalezeny žádné adresáře médií.
+ Nastavení automatického nahrávání
+ Nastavení
+ Okamžité nahrávání dat bylo kompletně předěláno. Navštivte hlavní menu a nakonfigurujte automatické nahrávání svých dat. Omlouváme se za nepříjemnosti.\n\nUžívejte si nové a rozšířené možnosti nahrávání dat!
+ Pro %1$s
- vybráno %d
- vybráno %d
@@ -666,7 +666,7 @@
Soukromí
Soubor nenalezen!
- Nastavení adresářů
+ Nastavení adresářů
Otestovat připojení k serveru
diff --git a/src/main/res/values-da/strings.xml b/src/main/res/values-da/strings.xml
index 7ccf79a53bcb..e3b9bec0d477 100644
--- a/src/main/res/values-da/strings.xml
+++ b/src/main/res/values-da/strings.xml
@@ -273,8 +273,8 @@
Forhåndsvisning af billede
%1$s kunne ikke kopieres til %2$s lokale mappe
Øjeblikkelig opload mappe
- Lokal mappe
- Ekstern mappe
+ Lokal mappe
+ Ekstern mappe
Benyt undermapper
Lagre i undermapper baseret på år og måned
@@ -391,15 +391,15 @@
Søg
Dette er en Nextcloud feature, opdater venligst
Lær mere
- Auto upload
+ Auto upload
Deltag
Release candidate
Flyt til…
Kopiér til…
Vælg mappe…
- Henter mapper…
- Ingen medie mappe fundet
- Indstillinger
+ Henter mapper…
+ Ingen medie mappe fundet
+ Indstillinger
Filnavn
Filtype
Standard
diff --git a/src/main/res/values-de-rDE/strings.xml b/src/main/res/values-de-rDE/strings.xml
index cacbc7497103..5e0a1ce40082 100644
--- a/src/main/res/values-de-rDE/strings.xml
+++ b/src/main/res/values-de-rDE/strings.xml
@@ -363,8 +363,8 @@
%1$s konnte nicht in den lokalen %2$s Ordner kopiert werden
Sofort-Upload-Ordner
- Lokales Verzeichnis
- Entferntes Verzeichnis
+ Lokales Verzeichnis
+ Entferntes Verzeichnis
Unterordner benutzen
In Unterordnern speichern, basierend auf Jahr und Monat
@@ -558,7 +558,7 @@
Suche
Dies ist eine Nextcloud Funktion, bitte updaten.
Mehr
- Automatisches Hochladen
+ Automatisches Hochladen
Mitmachen
Hilf uns Testen
Fehler gefunden? Komisches Verhalten?
@@ -578,12 +578,12 @@
Verschieben nach…
Kopieren nach…
Wähle Verzeichnis…
- Lade Verzeichnisse…
- Keine Medienverzeichnisse gefunden.
- Einstellungen Auto-Hochladen
- Einstellungen
- Sofortiger Upload wurde vollständig überarbeitet. Bitte über das Hauptmenü zum Auto Upload gehen und neu configurieren. Bitte entschuldige die Unannehmlichkeiten.\n\nViel Vergnügen mit den neuen und erweiterten Möglichkeiten des Auto Uploads.
- Für %1$s
+ Lade Verzeichnisse…
+ Keine Medienverzeichnisse gefunden.
+ Einstellungen Auto-Hochladen
+ Einstellungen
+ Sofortiger Upload wurde vollständig überarbeitet. Bitte über das Hauptmenü zum Auto Upload gehen und neu configurieren. Bitte entschuldige die Unannehmlichkeiten.\n\nViel Vergnügen mit den neuen und erweiterten Möglichkeiten des Auto Uploads.
+ Für %1$s
- %d ausgewählt
- %d ausgewählt
@@ -666,7 +666,7 @@
Datenschutz
Datei nicht gefunden!
- Ordner auswählen
+ Ordner auswählen
Prüfe Server-Verbindung
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index 8a4db1809a12..fdf0f29b60ae 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -363,8 +363,8 @@
%1$s konnte nicht in den lokalen %2$s Ordner kopiert werden
Sofort-Upload-Ordner
- Lokales Verzeichnis
- Entferntes Verzeichnis
+ Lokales Verzeichnis
+ Entferntes Verzeichnis
Unterordner benutzen
In Unterordnern speichern, basierend auf Jahr und Monat
@@ -559,7 +559,7 @@
Suche
Dies ist eine Nextcloud Funktion, bitte updaten.
Mehr
- Automatisches Hochladen
+ Automatisches Hochladen
Mitmachen
Hilf uns Testen
Fehler gefunden? Komisches Verhalten?
@@ -579,12 +579,12 @@
Verschieben nach…
Kopieren nach…
Wähle Verzeichnis…
- Lade Verzeichnisse…
- Keine Medienverzeichnisse gefunden.
- Einstellungen Auto-Hochladen
- Einstellungen
- Sofortiger Upload wurde vollständig überarbeitet. Bitte über das Hauptmenü zum Auto Upload gehen und neu configurieren. Bitte entschuldige die Unannehmlichkeiten.\n\nViel Vergnügen mit den neuen und erweiterten Möglichkeiten des Auto Uploads.
- Für %1$s
+ Lade Verzeichnisse…
+ Keine Medienverzeichnisse gefunden.
+ Einstellungen Auto-Hochladen
+ Einstellungen
+ Sofortiger Upload wurde vollständig überarbeitet. Bitte über das Hauptmenü zum Auto Upload gehen und neu configurieren. Bitte entschuldige die Unannehmlichkeiten.\n\nViel Vergnügen mit den neuen und erweiterten Möglichkeiten des Auto Uploads.
+ Für %1$s
- %d ausgewählt
- %d ausgewählt
@@ -667,7 +667,7 @@
Datenschutz
Datei nicht gefunden!
- Ordner auswählen
+ Ordner auswählen
Prüfe Server-Verbindung
diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml
index b6eefb850111..c203edab8164 100644
--- a/src/main/res/values-el/strings.xml
+++ b/src/main/res/values-el/strings.xml
@@ -362,8 +362,8 @@
Το %1$s δεν μπόρεσε να αντιγραφεί στον τοπικό φάκελο %2$s
Φάκελος άμεσης μεταφόρτωσης
- Τοπικός φάκελος
- Μετονομασία φακέλου
+ Τοπικός φάκελος
+ Μετονομασία φακέλου
Χρήση υποφακέλων
Αποθήκευση σε υποφακέλους με βάση το χρόνο και μήνα
@@ -557,7 +557,7 @@
Αναζήτηση
Αυτό είναι χαρακτηριστικό του Nextcloud, παρακαλούμε ενημερώστε.
Μάθετε περισσότερα
- Αυτόματη μεταφόρτωση
+ Αυτόματη μεταφόρτωση
Συμμετοχή
Βοηθήστε μας στις δοκιμές
Βρήκατε σφάλμα; Κάτι σας φαίνεται παράξενο;
@@ -577,12 +577,12 @@
Μετακίνηση σε…
Αντιγραφή σε…
Επιλογή φακέλου…
- Φόρτωση φακέλων…
- Δεν βρέθηκαν φάκελοι πολυμέσων.
- Προτιμήσεις αυτόματης μεταφόρτωσης
- Ρυθμίσεις
- Η άμεση μεταφόρτωση έχει ανανεωθεί τελείως. Παρακαλούμε δείτε το κυρίως μενού και ρυθμίστε ξανά την αυτόματη μεταφόρτωση. Σας ζητούμε συγγνώμη για την ενόχληση\n\nΑπολαύστε τις νέες και εκτεταμένες δυνατότητες της αυτόματης μεταφόρτωσης!
- Για %1$s
+ Φόρτωση φακέλων…
+ Δεν βρέθηκαν φάκελοι πολυμέσων.
+ Προτιμήσεις αυτόματης μεταφόρτωσης
+ Ρυθμίσεις
+ Η άμεση μεταφόρτωση έχει ανανεωθεί τελείως. Παρακαλούμε δείτε το κυρίως μενού και ρυθμίστε ξανά την αυτόματη μεταφόρτωση. Σας ζητούμε συγγνώμη για την ενόχληση\n\nΑπολαύστε τις νέες και εκτεταμένες δυνατότητες της αυτόματης μεταφόρτωσης!
+ Για %1$s
- %d επιλέχθηκε
- %d επιλέχθηκαν
@@ -665,7 +665,7 @@
Ιδιωτικότητα
Δεν βρέθηκε το αρχείο!
- Ρύθμιση φακέλων
+ Ρύθμιση φακέλων
Δοκιμή σύνδεσης με διακομιστή
diff --git a/src/main/res/values-en-rGB/strings.xml b/src/main/res/values-en-rGB/strings.xml
index 24c061746a89..136ded669c10 100644
--- a/src/main/res/values-en-rGB/strings.xml
+++ b/src/main/res/values-en-rGB/strings.xml
@@ -169,7 +169,7 @@
Upload failed, you need to log in again
Uploads
Current
- Failed (tap to retry)
+ Failed / Pending restart
Uploaded
Completed
Cancelled
@@ -362,8 +362,8 @@
%1$s could not be copied to %2$s local folder
Instant upload folder
- Local folder
- Remote folder
+ Local folder
+ Remote folder
Use subfolders
Store in subfolders based on year and month
@@ -557,7 +557,7 @@
Search
This is a Nextcloud feature, please update.
Learn more
- Auto upload
+ Auto upload
Participate
Help by testing
Found a bug? Oddments?
@@ -577,12 +577,12 @@
Move to…
Copy to…
Choose folder…
- Loading folders…
- No media folders found.
- Preferences for auto uploading
- Settings
- Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading.
- For %1$s
+ Loading folders…
+ No media folders found.
+ Preferences for auto uploading
+ Settings
+ Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading.
+ For %1$s
- %d selected
- %d selected
@@ -665,7 +665,7 @@
Privacy
File not found!
- Configure folders
+ Configure folders
Test server connection
diff --git a/src/main/res/values-es-rAR/strings.xml b/src/main/res/values-es-rAR/strings.xml
index e8fad3a34ce6..70b9f3370dc1 100644
--- a/src/main/res/values-es-rAR/strings.xml
+++ b/src/main/res/values-es-rAR/strings.xml
@@ -353,8 +353,8 @@
%1$s no pudo ser copiado a la carpeta local %2$s
Carpeta de carga instantánea
- Carpeta local
- Carpeta remota
+ Carpeta local
+ Carpeta remota
Usar sub carpetas
Almacenar en sub carpetas con base en el año y mes
@@ -535,7 +535,7 @@
Buscar
Esta es una característica de Nextcloud, favor de actualizar.
Conozca más
- Carga automática
+ Carga automática
Participe
Ayúdenos probando
¿Encontró una falla? ¿Hay algo raro?
@@ -547,12 +547,12 @@
Mover a…
Copiar a…
Seleccione la carpeta…
- Cargando carpetas…
- No se encontraron carpetas de medios
- Preferencias de carga automática
- Configuraciones
- La carga instantánea ha sido completamente moderinzada. Reconfigure su carga automática desde el menu principal. \n\nDisfrute de las nuevas y extendidas capacidades de la carga automática.
- Para %1$s
+ Cargando carpetas…
+ No se encontraron carpetas de medios
+ Preferencias de carga automática
+ Configuraciones
+ La carga instantánea ha sido completamente moderinzada. Reconfigure su carga automática desde el menu principal. \n\nDisfrute de las nuevas y extendidas capacidades de la carga automática.
+ Para %1$s
- %d seleccionado
- %d seleccionado
@@ -632,6 +632,6 @@
Privacidad
¡Archivo no encontrado!
- Configurar careptas
+ Configurar careptas
diff --git a/src/main/res/values-es-rMX/strings.xml b/src/main/res/values-es-rMX/strings.xml
index 103a3f795b6f..f184d9e9f4f9 100644
--- a/src/main/res/values-es-rMX/strings.xml
+++ b/src/main/res/values-es-rMX/strings.xml
@@ -362,8 +362,8 @@
%1$s no pudo ser copiado a la carpeta local %2$s
Carpeta de carga automática
- Carpeta local
- Carpeta remota
+ Carpeta local
+ Carpeta remota
Usar sub carpetas
Almacenar en sub carpetas con base en el año y mes
@@ -557,7 +557,7 @@
Buscar
Esta es una característica de Nextcloud, por favor actualiza.
Conoce más
- Carga automática
+ Carga automática
Participa
Ayúdanos probando
¿Encontraste una falla? ¿Hay algo raro?
@@ -577,12 +577,6 @@
Mover a…
Copiar a…
Seleccione la carpeta…
- Cargando carpetas…
- No se encontraron carpetas de medios
- Preferencias de carga automática
- Configuraciones
- La carga automática ha sido completamente moderinzada. Reconfigura tu carga automática desde el menu principal. \n\nDisfruta de las nuevas y extendidas capacidades de la carga automática.
- Para %1$s
- %d seleccionado
- %d seleccionado
@@ -665,7 +659,5 @@
Privacidad
¡Archivo no encontrado!
- Configurar carpetas
-
Probar la conexión del servidor
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index c26c2d8cb798..a4a4e7eb1383 100644
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -362,8 +362,8 @@
%1$s no se ha podido copiar a la carpeta local %2$s
Carpeta para subida instantánea
- Carpeta local
- Carpeta en servidor
+ Carpeta local
+ Carpeta en servidor
Usar subcarpetas
Almacenar en subcarpetas basadas en año y mes.
@@ -557,7 +557,7 @@
Buscar
Esta es una característica de Nextcloud. Por favor, actualice.
Aprender más
- Subida automática
+ Subida automática
Participar
Ayúdanos a realizar pruebas
¿Encontraste un error? ¿Algo va mal?
@@ -577,12 +577,12 @@
Mover a…
Copiar a…
Elija carpeta…
- Cargando carpetas…
- No se han encontrado carpetas de medios.
- Preferencias de subida automática
- Configuración
- La subida instantánea ha sido completamente renovada. Reconfigura tus subidas instantáneas en el menú principal.\n\n¡Disfruta las nuevas y extendidas capacidades de la subida automática!
- Durante %1$s
+ Cargando carpetas…
+ No se han encontrado carpetas de medios.
+ Preferencias de subida automática
+ Configuración
+ La subida instantánea ha sido completamente renovada. Reconfigura tus subidas instantáneas en el menú principal.\n\n¡Disfruta las nuevas y extendidas capacidades de la subida automática!
+ Durante %1$s
- %d seleccionado
- %d seleccionados
@@ -665,7 +665,7 @@
Privacidad
¡Archivo no encontrado!
- Configurar carpetas
+ Configurar carpetas
Probar conexión con servidor
diff --git a/src/main/res/values-fi-rFI/strings.xml b/src/main/res/values-fi-rFI/strings.xml
index c83b6ced574d..73d940410d35 100644
--- a/src/main/res/values-fi-rFI/strings.xml
+++ b/src/main/res/values-fi-rFI/strings.xml
@@ -290,8 +290,8 @@
Kuvan näyttäminen ei onnistunut
Välitön lähetys kansio
- Paikallinen kansio
- Etäkansio
+ Paikallinen kansio
+ Etäkansio
Käytä alikansioita
Tallenna alikansioihin vuoden ja kuukauden mukaisesti.
@@ -432,16 +432,16 @@
Etsi
Tämä on Nextcloudin ominaisuus, päivitä se.
Opi lisää
- Automaattinen lähetys
+ Automaattinen lähetys
Osallitu
Julkaisu ehdokas
Siirrä kohteeseen…
Kopio kohteeseen…
Valitse kansio…
- Ladataan kansiot…
- Media kansioita ei löytynyt.
- Asetukset
- %1$s varten
+ Ladataan kansiot…
+ Media kansioita ei löytynyt.
+ Asetukset
+ %1$s varten
- %d valittu
- %d valittu
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index 27d07cc1f241..7979b2a69408 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -362,8 +362,8 @@
%1$s n\'a pas pu être copié dans le dossier local %2$s
Téléversement immédiat du dossier
- Dossier local
- Dossier distant
+ Dossier local
+ Dossier distant
Utiliser des sous-dossiers
Stocker dans des sous-dossiers basés sur années et mois
@@ -557,7 +557,7 @@
Rechercher
Il s\'agit d\'une fonctionnalité de Nextcloud ; veuillez mettre à jour..
En apprendre plus
- Téléversement automatique
+ Téléversement automatique
Participer
Aidez nous en le testant
Vous avez trouvé un bug ? Quelque chose vous semble étrange ?
@@ -577,12 +577,12 @@
Déplacer vers…
Copier vers…
Sélectionner le dossier…
- Chargement des dossiers…
- Aucun dossier média trouvé.
- Préférences pour le téléversement automatique
- Paramètres
- Le téléversement immédiat a été complètement réorganisé. Merci de bien vouloir accéder au menu principal et de reconfigurer votre téléversement automatique.\n\nProfitez des nouvelles capacités étendues du téléversement automatique.
- Pour %1$s
+ Chargement des dossiers…
+ Aucun dossier média trouvé.
+ Préférences pour le téléversement automatique
+ Paramètres
+ Le téléversement immédiat a été complètement réorganisé. Merci de bien vouloir accéder au menu principal et de reconfigurer votre téléversement automatique.\n\nProfitez des nouvelles capacités étendues du téléversement automatique.
+ Pour %1$s
- %d sélectionné
- %d sélectionnés
@@ -665,7 +665,7 @@
Vie privée
Fichier non trouvé !
- Configurer les dossiers
+ Configurer les dossiers
Tester la connexion du serveur
diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml
new file mode 100644
index 000000000000..df16e34418a1
--- /dev/null
+++ b/src/main/res/values-gl/strings.xml
@@ -0,0 +1,664 @@
+
+
+ Aplicación %1$s Android
+ versión %1$s
+ Actualizar a conta
+ Enviar
+ Contido doutras aplicacións
+ Ficheiros
+ Abrir con
+ Novo cartafol
+ Axustes
+ Detalles
+ Enviar
+ Ordenar
+ Ordenar por
+ Ordenar por
+ A - Z
+ Z - A
+ Primeiro o máis recente
+ Primeiro o máis antigo
+ Primeiro o máis grande
+ Primeiro o máis pequeno
+
+ Todos os ficheiros
+ Ficheiros
+ Inicio
+ Favoritos
+ Fotos
+ No dispositivo
+ Engadido recentemente
+ Modificado recentemente
+ Compartido
+ Vídeos
+ Axustes
+ Envíos
+ Actividades
+ Notificacións
+ Usado %1$s de %2$s
+ Pechar
+ Abrir
+ Xeral
+ Máis
+ Contas
+ Xestionar as contas
+ Código de bloqueo
+ Bloqueo coa pegada dactilar
+ Non foi estabelecida ningunha pegada dactilar
+ Amosar os ficheiros agochados
+ Envío instantáneo de imaxes
+ Enviar instantaneamente as imaxes da cámara
+ Envío instantáneo de vídeos
+ Enviar instantaneamente os vídeos gravados coa cámara
+ Activar o rexistro
+ Isto empregase para rexistrar os problemas
+ Historial do rexistro
+ Isto amosa os rexistros gravados
+ Eliminar o historial
+ Sincronizar calendario e contactos
+ Configurar DAVdroid (v1.3.0 +) para a conta actual
+ DAVdroid non foi quen de resolver o enderezo do servidor para a conta
+ Nin F-Droid nin Google Play están instalados
+ Configurada a sincronización do calendario e dos contactos
+ Axuda
+ Recomendar a un amigo
+ Comentarios
+ Exención de responsabilidade
+ Lembrar a localización do elemento compartido
+ Lembrar a localización do elemento compartido usado máis recentemente
+
+ Probe %1$s no seu teléfono intelixente!
+ Quixera convidalo a usar %1$s no seu teléfono intelixente\nDescargueo aquí: %2$s
+
+ Comprobar o servidor
+ Enderezo do servidor https://…
+ Nome de usuario
+ Contrasinal
+ Aínda non ten un servidor? \nPrema aquí para obter un dun provedor
+ Ficheiros
+ Conectar
+ Enviar
+ Seleccione o cartafol de envío
+ Non se atoparon contas
+ Non existen contas %1$s no seu dispositivo. Configure primeiro unha conta.
+ Instalación
+ Saír
+ Non hai ficheiros para enviar
+ %1$s non pode enviar un fragmento de texto coma se for un ficheiro.
+ Os datos recibidos non inclúen un ficheiro correcto.
+ Non é posíbel enviar este ficheiro
+ %1$s non ten permisos para ler o ficheiro recibido
+ Non foi atopado o ficheiro seleccionado para enviar. Comprobe se existe o ficheiro
+ Non foi posíbel copiar o ficheiro nun cartafol temporal. Tente volver envialo.
+ Opción de envío:
+ Mover o ficheiro cara o cartafol de Nextcloud
+ Manter o ficheiro no cartafol de orixe
+ Eliminar o ficheiro do cartafol de orixe
+ segundos atrás
+ Aquí non hai ficheiros
+ Envíe algún contido ou sincronice cos seus dispositivos
+ Marque como favoritos algúns ficheiros ou sincronice cos seus dispositivos!
+ Os ficheiros e cartafoles que marque como favoritos amosaranse aquí
+ A súa busca non atopou ningún ficheiro favorito.
+ Cargando…
+ Non foi estabelecida unha aplicación para manexar este tipo de ficheiro.
+ Non hai ficheiros neste cartafol.
+ Non hai resultados neste cartafol
+ Sen resultados
+ Aínda non hay nada marcado como favorito
+ Aínda non hay nada compartido
+ Os ficheiros e cartafoles que comparta amosaranse aquí
+ Non hai vídeos
+ Non hai fotos
+ Quizáis estea nun cartafol diferente?
+ Non se atoparon ficheiros modificados nos últimos 7 días.
+ A súa busca non atopou ficheiros que teñan sido modificados
+nos últimos 7 días.
+ Non se atoparon ficheiros engadidos recentemente
+ A súa busca non atopou ningún ficheiro engadido recentemente.
+ Envíe algunhas fotos ou active o envío automático.
+ A súa busca non atopou ningunha fotografía.
+ Envíe algún vídeo ou active o envío automático.
+ A súa busca non atopou ningún vídeo.
+ Non hai envío dispoñíbeis
+ Envíe algún contido ou active o envío automático.
+ Envíe algún contido ou active o envío automático.
+ cartafol
+ cartafoles
+ ficheiro
+ ficheiros
+ Toque nun ficheiro para que amose a información adicional.
+ Tamaño:
+ Tipo:
+ Creado:
+ Modificado:
+ Descargar
+ Sincronizar
+ O ficheiro foi renomeado a %1$s durante o envío
+ Ver como lista
+ Compartir
+ Si
+ Non
+ Aceptar
+ Retirar o envío
+ Tentar de novo o envío
+ Cancelar a sincronización
+ Cancelar
+ Atrás
+ Gardar
+ Gardar e saír
+ Erro
+ Cargando …
+ descoñecido
+ Produciuse un erro descoñecido
+ Pendente
+ Sobre
+ Cambiar o contrasinal
+ Retirar a conta
+ Eliminar a conta %s?\n\n Esta acción non pode desfacerse.
+ Crear unha conta
+ Enviar desde …
+ Nome do cartafol
+ Enviando …
+ %1$d%% enviando %2$s
+ Enviado
+ Enviado %1$s
+ Produciuse unha falla no envío
+ Non foi posíbel enviar: %1$s
+ O envío fracasou, é necesario que se autentique de novo.
+ Envíos
+ Actual
+ Produciuse unha falla (toque para volver tentalo)
+ Enviado
+ Completado
+ Cancelado
+ Pausado
+ Produciuse un erro de conexión
+ En breve volverá a iniciarse o envío
+ Produciuse un erro de credenciais
+ Produciuse un erro de cartafol
+ Produciuse un erro de ficheiro
+ Non se atopou o ficheiro local
+ Erro nos permisos
+ Conflito
+ A aplicación interrompeuse
+ Produciuse un erro descoñecido
+ Agardando pola conexión WiFi
+ Agardando polo envío
+ Descargando …
+ %1$d%% descargando %2$s
+ Descargado
+ Descargando %1$s
+ Produciuse unha falla na descarga
+ Non foi posíbel descargar %1$s
+ Non descargado aínda
+ A descarga fracasou, é necesario que se autentique de novo.
+ Escoller unha conta
+ Produciuse unha falla na sincronización
+ Produciuse unha falla na sincronización, é necesario que se autentique de novo.
+ Non foi posíbel completar a sincronización de %1$s
+ Contrasinal incorrecto para %1$s
+ Atopáronse conflictos
+ %1$d ficheiros «manter sincronizados» non foi posíbel sincronizalos
+ Produciuse unha falla no mantemento sincronizado de ficheiros
+ Non foi posíbel sincronizar o contido de %1$d ficheiros (%2$d conflitos)
+ Algúns ficheiros locais foron esquecidos
+ Non é posíbel copiar %1$d ficheiros do cartafol %2$s en
+ A partires da versión 1.3.16, os ficheiros enviados desde este dispositivo cópianse no cartafol local %1$s para evitar a perda de datos cando se sincroniza un único ficheiro con varias contas.\n\nPor mor deste cambio, todos os ficheiros enviados con versións anteriores desta aplicación foron copiados no cartafol %2$s. Porén, un erro impediu que se completara esta operación durante a sincronización da conta. Pode deixar os ficheiros tal e como están e eliminar a ligazón cara %3$s ou mover los ficheiros para o cartafol %1$s e manter a ligazón cara %4$s.\n\nEmbaixo amósanse os ficheiros locais e os ficheiros remotos en %5$s aos que foron enlazados.
+ O cartafol %1$s xa non existe
+ Mover todo
+ Foron movidos todos os ficheiros
+ Algúns ficheiros non puideron seren movidos
+ Local: %1$s
+ Remoto: %1$s
+ Non hai espazo abondo para copiar os ficheiros seleccionados no cartafol %1$s. No canto diso, gustaríalle movelos?
+ Introduza o seu código de seguridade
+
+ Introduza o seu código de seguridade
+ Solicitaráselle o código de seguridade cada vez que inicie a aplicación
+ Introduza de novo o seu código de seguridade
+ Retirar o seu código de seguridade
+ Os códigos de seguridade non son iguais
+ Código de seguridade incorrecto
+ Retirouse o código de seguridade
+ O código de seguridade foi almacenado
+
+ %1$s reprodutor musical
+ %1$s (reproducindo)
+ %1$s (cargando)
+ Rematou a reprodución de %1$s
+ Non se atopan ficheiros multimedia
+ Non foi fornecida unha conta
+ O ficheiro non está nunha conta correcta
+ Códec multimedia non admitido
+ Non foi posíbel ler o ficheiro multimedia
+ O ficheiro multimedia ten unha codificación incorrecta
+ O intento de reproducir o ficheiro esgotou o tempo de espera.
+ O ficheiro multimedia non pode ser transformado nun fluxo
+ O reprodutor predeterminado non pode reproducir o ficheiro mltimedia
+ Produciuse un erro de seguridade ao tentar reproducir %1$s
+ Produciuse un erro de entrada ao tentar reproducir %1$s
+ Produciuse un erro non agardado ao tentar reproducir %1$s
+ Botón de retroceso
+ Botón de reprodución/pausa
+ Botón de avance rápido
+
+ Obtendo autorización …
+ Tentando acceder a …
+ Sen conexión de rede
+ Non hai conexións seguras dispoñíbeis.
+ Estabeleceuse a conexión
+ Probando a conexión
+ Configuración errada do servidor
+ Xa existe unha conta en este dispositivo cos mesmos datos de usuario e servidor
+ O usuario que inseriu non coincide co usuario desta conta
+ Produciuse un erro descoñecido!
+ Non foi posíbel atopar a máquina
+ Non se atopou o servidor
+ O servidor tardou de máis en responder
+ O formato do enderezo do servidor é incorrecto
+ Produciuse unha falla ao preparar o SSL
+ Non foi posíbel verificar a identidade do servidor SSL
+ Versión do servidor non recoñecida
+ Non foi posíbel establecer a conexión
+ Estabeleceuse unha conexión segura
+ Nome de usuario ou contrasinal incorrecto
+ A autorización non foi aceptada
+ O acceso foi denegado polo servidor de autorización
+ Estado non agardado; introduza de novo o enderezo do servidor
+ A súa autorización caducou. Autorícese de novo
+ Introduza o seu contrasinal actual
+ A súa sesión caducou. Acceda de novo
+ Conectando co servidor de autenticación…
+ O servidor non admite este método de autenticación
+ %1$s non admite contas múltipes
+ O seu servidor non está devolvendo unha identificación de usuario correcta; contacte cun administrador
+ Non é posíbel autenticarse neste servidor
+ A conta aínda non existe no dispositivo
+
+
+ Estabelecer como dispoñíbel sen conexión
+ Estabelecer como dispoñíbel con conexión
+ Estabelecer como favorito
+ Retirar de favoritos
+ Renomear
+ Retirar
+ Confirma que quere retirar %1$s?
+ Confirma que quere retirar %1$s e todo o seu contido?
+ Só local
+ Retirado
+ Non foi posíbel retiralo
+ Introduza un nome novo
+ Non foi posíbel renomear a copia local, ténteo cun un nome diferente
+ Non foi posíbel renomear o servidor
+ Non foi posíbel comprobar o ficheiro remoto
+ Os contidos do ficheiro xa están sincronizados
+ Non foi posíbel crear o cartafol
+ Caracteres non permitidos: / \\ < > : \" | ? *
+ O nome de ficheiro contén algún carácter incorrecto
+ O nome de ficheiro non pode estar baleiro
+ Agarde un chisco
+ Comprobando as credenciais almacenadas
+ Produciuse un problema non agardado, seleccione o ficheiro desde una aplicación diferente
+ Non seleccionou ningún ficheiro
+ Enviar a ligazón a …
+ Copiando o ficheiro desde o almacenamento privado
+
+ Acceder con oAuth2
+ Conectando co servidor oAuth2…
+
+ Non foi posíbel verificar a identidade do sitio
+ - O certificado do servidor non é de confianza
+ - O certificado do servidor caducou
+ - As datas de validez do certificado están son do futuro
+ - O URL non coincide co nome de máquina no certificado
+ Aínda así, quere fiar neste certificado igualmente?
+ Non foi posíbel gardar o certificado
+ Detalles
+ Agochar
+ Emitido para:
+ Emitido por:
+ Nome común:
+ Organización:
+ Departamento da organización:
+ País
+ Estado:
+ Lugar:
+ Validez:
+ De:
+ A:
+ Sinatura:
+ Algoritmo:
+ Este algoritmo de resumo non está dispoñíbel no seu teléfono.
+ Pegada dactilar
+ Existe un problema ao cargar o certificado.
+ Non é posíbel amosar o certificado.
+ - Non hai información sobre este erro
+
+ Isto é un marcador de posición
+ placeholder.txt
+ Imaxe PNG
+ 389 KB
+ 2012/05/18 12:23 PM
+ 12:23:45
+
+ Enviar só con WiFi
+ Enviar fotografías só con WiFi
+ Enviar vídeos só con WiFi
+ Enviar só cando estea cargando
+ Enviar só cando estea cargando
+ /EnvíoInstantáneo
+ /Envío automático
+ Conflito de ficheiro
+ Que ficheiros quere manter? Se selecciona ámbalas dúas versións, engadiráselle un número ao nome do ficheiro local.
+ Manter ambos
+ versión local
+ versión no servidor
+
+ Disculpe.
+ Vista previa da imaxe
+ Non é posíbel amosar a imaxe
+
+ Non foi posíbel copiar %1$s no cartafol local %2$s
+ Cartafol de envío instántaneo
+ Cartafol local
+ Cartafol remoto
+ Usar subcartafoles
+ Arquivar en subcartafoles baseados en ano e mes.
+
+ O seu servidor non ten activada a compartición. Póñase en contacto co administrador
+ Non se puido actualizar. Comprobe que o ficheiro existe
+ Produciuse un erro ao tentar compartir este ficheiro ou cartafol
+ Non foi posíbel deixar de compartir. Comprobe que existe o ficheiro
+ Produciuse un erro ao tentar deixar de compartir este ficheiro ou cartafol
+ Non se puido actualizar. Comprobe que o ficheiro existe
+ Produciuse un erro ao tentar actualizar o elemento compartido
+ Escriba un contrasinal
+ Ten que escribir un contrasinal
+
+ Enviar
+
+ Copiar a ligazón
+ Copiado no portapapeis.
+ Non se ha recibiu ningún texto para copiar no portapapeis
+ Produciuse un erro non agardado ao copiar no portapapeis
+ Texto copiado desde %1$s
+
+ produciuse un erro crítico: Non é posíbel realizar operacións
+
+ produciuse un erro durante a conexión co servidor
+ Produciuse un erro agardando a resposta do servidor. Non foi posíbel completar a operación.
+ Produciuse un erro agardando a resposta do servidor. Non foi posíbel completar a operación.
+ Non foi posíbel completar a operación. O servidor non está dispoñíbel
+
+ Non ten permiso %s
+ para renomear este ficheiro
+ para eliminar este ficheiro
+ para compartir este ficheiro
+ para deixar de compartir este ficheiro
+ para actualizar esta compartición
+ para crear este ficheiro
+ para enviar este cartafol
+ O ficheiro xa non está dispoñíbel no servidor
+
+ Actualizando a ruta do almacenamento
+ Rematar
+ Preparando a migración…
+ Comprobando o destino…
+ Gardando a configuración das contas…
+ Agardando que rematen todas as sincronizacións…
+ Movendo datos…
+ Actualizando o índice…
+ Limpando…
+ Restaurando a configuración das contas…
+ Rematado
+ ERRO: Non hai espazo abondo
+ ERRO: Non se pode escribir no ficheiro de destino
+ ERRO: Non se pode ler o ficheiro de orixe
+ ERRO: xa existe o directorio de Nextcloud
+ ERRO: Produciuse unha falla durante a migración
+ ERRO: Produciuse unha falla ao actualizar o índice
+
+ Xa existe o cartafol de datos. Escolla un dos seguintes:
+ Substituír
+ Usar
+
+ Non se pode ler o ficheiro de orixe
+ Aínda quere cambiar a ruta do almacenamento a |%1$s?\n\nNota: haberá que volver descargar todos os datos.
+
+ Contas
+ Engadir unha conta
+ Administrar contas
+ A conexión segura está a ser redirixida a través dunha ruta insegura.
+
+ Rexistros
+ Enviar o historial
+ Non se atopou ningunha aplicación para o envío de rexistros. Instale un cliente de correo-e.
+ Rexistros da aplicación %1$s Android
+ Cargando datos …
+
+ Requírese autenticación
+ Contrasinal incorrecto
+ Mover
+ Copiar
+ Aquí non hai nada. Pode engadir un cartafol.
+ Escoller
+
+ Non se puido mover o ficheiro. Comprobe que o ficheiro existe
+ Non é posíbel mover un cartafol cara un dos seus propios cartafoles
+ Este ficheiro xa existe no cartafol de destino
+ Produciuse un erro ao tentar mover este ficheiro ou cartafol.
+ para mover este ficheiro
+
+
+ Non se puido copiar. Comprobe que o ficheiro existe
+ Non é posíbel copiar un cartafol nun dos seus propios cartafoles
+ Este ficheiro xa existe no cartafol de destino
+ Oconteceu un erro mentras se intentaba copiar este ficheiro ou cartafol
+ copiar este ficheiro
+
+ Envíos instantáneos
+ Detalles
+
+ Cartafol de vídeo para envíos instantáneos
+ A sincronización do cartafol %1$s non se completou
+
+ compartido
+ con vostede
+
+ %1$s compartiu «%2$s» con vostede
+ «%1$s» foi compartido con vostede
+
+ Actualizar a conexión
+ Enderezo do servidor
+ Non hai memoria abondo
+
+ Nome de usuario
+
+ 1 cartafol
+ %1$d cartafoles
+ 1 ficheiro
+ 1 ficheiro, 1 cartafol
+ 1 ficheiro, %1$d cartafoles
+ %1$d ficheiros
+ %1$d ficheiros, 1 cartafol
+ %1$d ficheiros, %2$d cartafoles
+ Establecer a imaxe como
+ Estabelecer como
+
+ O ficheiro orixinal vai ser…
+ O ficheiro orixinal vai ser…
+ Copiar o ficheiro
+ Mover o ficheiro
+ Seleccionar todo
+
+ mantense no cartafol orixinal
+ movido car o cartafol da aplicación
+ eliminado
+ Ruta de almacenamento
+ Común
+
+ Compartindo
+ Compartir con %1$s
+ Compartir con outros usuarios e grupos
+ Aínda non hai datos compartidos con usuarios
+ Engadir usuario ou grupo
+ Compartir ligazón
+ Definir a data de caducidade
+ Protexer con contrasinal
+ Asegurado
+ Permitir a edición
+ Agochar a lista de ficheiros
+ Obter a ligazón
+ Compartir con …
+ Compartir con %1$s
+
+ Buscar
+
+ Buscar usuarios e grupos
+ %1$s (grupo)
+ %1$s (remoto)
+ %1$s (correo-e)
+ %1$s ( ás %2$s )
+
+ Actualice a versión do servidor para permitir compartir entre usuarios dende os seus clientes.\nContacte co administrador
+ pode compartir
+ pode editar
+ crear
+ cambio
+ eliminar
+ Deixar de compartir
+ feito
+
+ Fracasou o novo intento
+ Fracasou a limpeza
+ Limpo
+ Limpar os envíos rematados
+
+ Vista como grella
+ Vista como lista
+
+ Administrar o espazo
+ Van ser eliminados permanentemente as configuracións , base de datos e certificados do servidor de datos de %1$s.\n\nOs ficheiros descargados manteranse sen cambios.\n\nEste proceso pode levar bastante tempo.
+ Limpar os datos
+ Algúns ficheiros non puideron ser eliminados
+
+ Requirense permisos adicionais para enviar e descargar ficheiros.
+ Non se atopou o ficheiro no sistema local de ficheiros
+ Confirma que quere retirar os elementos seleccionados?
+ Confirma que quere retirar os elementos seleccionados e o seu contido?
+ Servidor en modo de mantemento
+
+ Agardando pola carga
+ Buscar
+ Esta é unha funcionalidade de Nextcloud, actualice.
+ Aprender máis
+ Envío automático
+ Participar
+ Axudanos facendo probas
+ Atopaches un fallo? hai algo estraño?
+ Informe dun fallo no GitHub
+ Iinteresaríalle axudarnos a probar a seguinte versión?
+ Probar a versión de desenvolvemento
+ Isto inclúe todas las últimas funcionalidades y es lo más nuevo. Poden ocorrer fallas e erros e, se é o caso, infórmenos diso.
+ Candidata de publicación
+ A candidata de publicación (release candidate - RC) é unha foto da versión máis proxima a publicar e agardase que sexa estábel. Probar a súa configuración individual podería axudarnos a asegurar iso. Rexístrese para facer probas na Play Store ou consulte directamente a sección de «versións» en F-Droid.
+ Colabore activamente
+ Únase ás conversas no IRC: <a href=\\"%1$s\\">#nextcloud-mobile</a>
+ Axude a outros no <a href=\\"%1$s\\">foro</a>
+ <a href=\\"%1$s\\">Traduza</a> a aplicación
+ Revise, corrixa e escriba código, vexa <a href=\\"%1$s\\">CONTRIBUIR.md</a> para obter máis detalles
+ Mover para…
+ Copiar en…
+ Escolla o cartafol…
+ Cargando cartafoles…
+ Non se atopan cartafoles multimedia
+ Preferencias de envío automático
+ Axustes
+ O envío automático foi renovado completamente. Reconfigure os seus envíos instantáneos no menú principal.\n\nGoce das novas e ampliadas capacidades do envío automático!
+ Para %1$s
+
+ - %d selecionado
+ - %d selecionados
+
+
+ Cargando actividades…
+ Non se atoparon actividades.
+
+ Cargando notificacións…
+ Non hai notificacións
+ Compróbeo máis tarde.
+
+ Introduza o nome e o tipo do ficheiro a enviar
+ Nome de ficheiro
+ Tipo de ficheiro
+ Fragmento de teto(.txt)
+ Ficheiro de atallo a internet(%s)
+ Ficheiro de atallo aGoogle Maps(%s)
+
+ Predeterminado
+ Tarxeta SD %1$d
+ Descoñecido
+
+
+ Que hai de novo no Nextcloud
+
+
+ Un lugar seguro para todos os seus datos
+ Acceda, comparta e protexa os seus ficheiros na casa e na oficina
+
+ Múltiples contas
+ Conéctese a todas as aúas nubes
+
+ Envío instantáneo
+ Manteña as súas fotos a seguro
+
+ Omitir
+
+ Escanée o seu dedo
+ O dedo non foi recoñecido
+
+
+ Nome completo
+ Correo-e
+ Número de teléfono
+ Enderezo
+ Sitio web
+ Twitter
+
+ Información do usuario
+
+
+ Aínda non houbo actividade
+ Este fluxo amosaralle eventos como\nadicións, cambios e elementos compartidos
+ Produciuse un erro
+ Sobre
+
+ Copia de seguridade dos contactos
+ Restaurar os contactos
+ Facer agora a copia de seguridade
+ Copia de seguridade dos contactos
+ Última copia de seguridade
+ Necesitase permiso para ler a lista de contactos
+ Necesitase permiso para cambiar a lista de contactos
+ Restaurar os contactos
+ Restaurar os contactos seleccionados
+ Escolla unha conta para importala
+ Non se concederon permisos. Non se importou nada!
+ Escolla a data
+ nunca
+ Non se atopou o ficheiro
+ Non foi posíbel atopar a súa última copia de seguridade!
+ A copia de seguridade está programada e comezará en breve
+ A importación está programada e comezará en breve
+
+
+ Recibiuse unha nova notificación
+ Saír
+ Non se atopou unha aplicación coa que estabelecer unha imaxe!
+ Intimidade
+ Non se atopou o ficheiro!
+
+ Configurar os cartafoles
+
+
diff --git a/src/main/res/values-he/strings.xml b/src/main/res/values-he/strings.xml
index aa25048961ca..fbd1e227e647 100644
--- a/src/main/res/values-he/strings.xml
+++ b/src/main/res/values-he/strings.xml
@@ -223,8 +223,8 @@
תצוגה מקדימה לתמונה
%1$s לא ניתן להעתקה לתיקייה מקומית %2$s
- תיקייה מקומית
- תיקייה מרוחקת
+ תיקייה מקומית
+ תיקייה מרוחקת
לא ניתן לשתף. יש לבדוק אם הקובץ קיים
שגיאה אירעה בזמן ניסיון לשתף קובץ זה או תיקייה זו
לא ניתן לבטל שיתוף. יש לבדוק אם הקובץ קיים
@@ -350,8 +350,8 @@
העתק אל…
בחר תיקייה…
- לא נמצאו תיקיות מדיה
- הגדרות
+ לא נמצאו תיקיות מדיה
+ הגדרות
שם קובץ
סוג קובץ
ברירת מחדל
diff --git a/src/main/res/values-hu-rHU/strings.xml b/src/main/res/values-hu-rHU/strings.xml
index 35c607551093..9b09ad338df2 100644
--- a/src/main/res/values-hu-rHU/strings.xml
+++ b/src/main/res/values-hu-rHU/strings.xml
@@ -293,8 +293,8 @@
Előnézeti kép
%1$s nem lehet másolni a %2$s helyi mappába
Azonnali feltöltés mappa
- Helyi mappa
- Távoli mappa
+ Helyi mappa
+ Távoli mappa
Almappák használata
Tárolás év és hónap szerinti almappákban
@@ -429,17 +429,19 @@
Keresés
Ez egy Nextcloud funkció, kérlek frissíts.
Tudj meg többet
- Automatikus feltöltés
+ Automatikus feltöltés
Részvétel
Kiadásra jelölt
Aktívan hozzájárul
Áthelyezés ide...…
Másolás ide...…
Mappa választás…
- Mappák betöltése…
- Nem találhatók média mappák.
- Beállítások
- Neki: %1$s
+ Mappák betöltése…
+ Nem találhatók média mappák.
+ Automatikus feltöltés beállításai
+ Beállítások
+ Az azonnali feltöltés teljesen át lett alakítva. Kérlek a főmenüben állítsd be újra az automatikus feltöltést. Elnézést a kellemetlenségért.\n\nÉlvezd az új és kibővített automatikus feltöltési képességet!
+ Neki: %1$s
- %d kiválasztott
- %d kiválasztott
diff --git a/src/main/res/values-id/strings.xml b/src/main/res/values-id/strings.xml
index 0eaba31f98bf..ef52265327fa 100644
--- a/src/main/res/values-id/strings.xml
+++ b/src/main/res/values-id/strings.xml
@@ -238,8 +238,8 @@
Pratilik gambar
%1$s tidak dapat disalin ke folder lokal %2$s
Folder unggah cepat
- Folder lokal
- Folder remote
+ Folder lokal
+ Folder remote
Gunakan subfolder
Simpan dalam subfolder berdasarkan tahun dan bulan
@@ -374,17 +374,19 @@
Cari
Ini adalah fitur Nextcloud, harap perbarui.
Pelajari lebih lanjut
- Unggah otomatis
+ Unggah otomatis
Berpartisipasi
Kandidat rilis
Berkontribusi Aktif
Pindah ke…
Salin ke…
Pilih folder…
- Memuat folder…
- Tidak ada folder media yang ditemukan.
- Pengaturan
- Untuk %1$s
+ Memuat folder…
+ Tidak ada folder media yang ditemukan.
+ Preferensi unggah otomatis
+ Pengaturan
+ Unggah instan telah dirubah sepenuhnya. Harap lihat menu utama dan konfigurasi ulang unggah otomatis anda. Maaf untuk gangguannya.\n\nNikmati kemampuan unggah otomatis yang lebih jauh dan baru!
+ Untuk %1$s
- %d dipilih
diff --git a/src/main/res/values-is/strings.xml b/src/main/res/values-is/strings.xml
index be1d8e1e8f8e..bba2cb902292 100644
--- a/src/main/res/values-is/strings.xml
+++ b/src/main/res/values-is/strings.xml
@@ -363,8 +363,8 @@ Smelltu hér til að fá þér einn frá þjónustuaðila.
%1$s var ekki hægt að afrita í staðværu %2$s möppuna
Mappa fyrir beinar innsendingar
- Staðvær mappa
- Fjartengd mappa
+ Staðvær mappa
+ Fjartengd mappa
Nota undirmöppur
Geyma í undirmöppum byggðum á ári og mánuðum
@@ -558,7 +558,7 @@ Smelltu hér til að fá þér einn frá þjónustuaðila.
Leita
Þetta er Nextcloud-eiginleiki, endilega uppfærðu.
Læra meira
- Sjálfvirk innsending
+ Sjálfvirk innsending
Taka þátt
Hjálpaðu til við prófanir
Fannstu villu? Skringilegheit?
@@ -578,12 +578,12 @@ Smelltu hér til að fá þér einn frá þjónustuaðila.
Færa í…
Afrita í…
Veldu möppu…
- Hleð inn möppum…
- Engar margmiðlunarmöppur fundust
- Kjörstillingar fyrir sjálfvirkar innsendingar
- Stillingar
- Beinar innsendingar hafa verið algerlega endurhannaðar. Endurstilltu sjálfvirkar innsendingar beint í aðalvalmyndinni\n\nNjóttu góðs af nýju og ítarlegu viðmóti sjálfvirkra innsendinga.
- Fyrir %1$s
+ Hleð inn möppum…
+ Engar margmiðlunarmöppur fundust
+ Kjörstillingar fyrir sjálfvirkar innsendingar
+ Stillingar
+ Beinar innsendingar hafa verið algerlega endurhannaðar. Endurstilltu sjálfvirkar innsendingar beint í aðalvalmyndinni\n\nNjóttu góðs af nýju og ítarlegu viðmóti sjálfvirkra innsendinga.
+ Fyrir %1$s
- %d valið
- %d valið
@@ -666,7 +666,7 @@ Smelltu hér til að fá þér einn frá þjónustuaðila.
Gagnaleynd
Skrá finnst ekki!
- Stilla möppur
+ Stilla möppur
Prófa tengingu þjóns
diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml
index 27166d5d0c59..40ea26fdefdc 100644
--- a/src/main/res/values-it/strings.xml
+++ b/src/main/res/values-it/strings.xml
@@ -296,8 +296,8 @@
%1$s non può essere copiato nella cartella locale %2$s
Cartella caricamenti istantanei
- Cartella locale
- Cartella remota
+ Cartella locale
+ Cartella remota
Usa sottocartelle
Archivia in sottocartelle in base a anno e mese
@@ -454,7 +454,7 @@
Cerca
Questa è una funzionalità di Nextcloud, aggiorna.
Scopri altro
- Carica automaticamente
+ Carica automaticamente
Partecipa
Prova la versione di sviluppo
Candidata al rilascio
@@ -462,10 +462,10 @@
Sposta in…
Copia in…
Scegli la cartella…
- Caricamento cartelle…
- Nessuna cartella di file multimediali trovata.
- Impostazioni
- Per %1$s
+ Caricamento cartelle…
+ Nessuna cartella di file multimediali trovata.
+ Impostazioni
+ Per %1$s
- %d selezionato
- %d selezionati
@@ -536,6 +536,6 @@
Riservatezza
File non trovato!
- Configura cartelle
+ Configura cartelle
diff --git a/src/main/res/values-ja-rJP/strings.xml b/src/main/res/values-ja-rJP/strings.xml
index 130628c2279e..07b0e5093f15 100644
--- a/src/main/res/values-ja-rJP/strings.xml
+++ b/src/main/res/values-ja-rJP/strings.xml
@@ -290,8 +290,8 @@
イメージプレビュー
%1$s は、ローカルフォルダー %2$s にコピーできませんでした。
自動アップロードフォルダー
- ローカルフォルダー
- リモートフォルダー
+ ローカルフォルダー
+ リモートフォルダー
サブフォルダーを利用
年と月を元にしたサブフォルダーに保存
@@ -426,7 +426,7 @@
検索
これはNextCloudの機能です。更新してください。
もっと見る
- 自動アップロード
+ 自動アップロード
参加する
開発バージョンをテスト
リリース候補
@@ -434,10 +434,10 @@
…に移動
…にコピー
… フォルダーを選択
- … フォルダを読み込み中
- メディアフォルダが見つかりませんでした
- 設定
- %1$s の
+ … フォルダを読み込み中
+ メディアフォルダが見つかりませんでした
+ 設定
+ %1$s の
- %d選択されています。
diff --git a/src/main/res/values-lv/strings.xml b/src/main/res/values-lv/strings.xml
index 2acbb9550c17..8ca536a79f2d 100644
--- a/src/main/res/values-lv/strings.xml
+++ b/src/main/res/values-lv/strings.xml
@@ -252,8 +252,8 @@
Attēla priekšskatījums
%1$s nevar kopēt uz %2$s lokālo mapi
Tūlītējas augšupielādes mepe
- Lokāla mape
- Attālinātā mape
+ Lokāla mape
+ Attālinātā mape
Lietot apakšmapi
Nevar koplietot. Lūdzu, pārbaudiet, vai fails pastāv
Radās kļūda, mēģinot koplietot šo failu vai mapi
@@ -377,14 +377,19 @@
Vai tiešām vēlies noņemt izvēlētos un to saturu?
Meklēt
Uzziniet vairāk
- Automātiska augšupielāde
+ Automātiska augšupielāde
+ Palīdziet mums testēšanā
+ Ziņojiet par problēmu Github
+ Pievienojieties tērzēšanas ar IRC: <a href=\"%1$s\">#nextcloud-mobile</a>
+ Palīdziet citiem <a href=\"%1$s\">forumā</a>
+ <a href="%1$s">Tūlkot</a> programmu
Pārvietot uz…
Kopēt uz…
Izvēlies mapi…
- Ielāde mapes…
- Nav atrasta multivides mape.
- Iestatījumi
- %1$s
+ Ielāde mapes…
+ Nav atrasta multivides mape.
+ Iestatījumi
+ %1$s
- %d atlasīts
- %d atlasīts
diff --git a/src/main/res/values-nb-rNO/strings.xml b/src/main/res/values-nb-rNO/strings.xml
index 06b11f0ef2a7..025abc842332 100644
--- a/src/main/res/values-nb-rNO/strings.xml
+++ b/src/main/res/values-nb-rNO/strings.xml
@@ -362,8 +362,8 @@
%1$s kunne ikke kopieres til lokal mappe %2$s
Mappe for umiddelbar opplasting
- Lokal mappe
- Ekstern mappe
+ Lokal mappe
+ Ekstern mappe
Bruk undermapper
Lagre filer i undermapper basert på år og måned
@@ -556,7 +556,7 @@
Søk
Dette er en Nextcloud funksjon, oppdater.
Lær mer
- Auto-opplasting
+ Auto-opplasting
Delta
Hjelp oss å teste
Funnet en feil? Føles noe rart?
@@ -575,12 +575,12 @@
Flytt til…
Kopier til…
Velg mappe…
- Laster inn mapper…
- Ingen mediamapper funnet.
- Innstillinger for auto-opplasting
- Innstillinger
- Umiddelbar opplasting er fullstendig omarbeidet. Se hovedmenyen og konfigurer auto-opplasting på nytt. Beklager uleiligheten.\n\nTa i bruk de nye og utvidede mulighetene i auto-opplasting.
- For %1$s
+ Laster inn mapper…
+ Ingen mediamapper funnet.
+ Innstillinger for auto-opplasting
+ Innstillinger
+ Umiddelbar opplasting er fullstendig omarbeidet. Se hovedmenyen og konfigurer auto-opplasting på nytt. Beklager uleiligheten.\n\nTa i bruk de nye og utvidede mulighetene i auto-opplasting.
+ For %1$s
- %d valgt
- %d valgte
@@ -663,7 +663,7 @@
Personvern
Finner ikke filen!
- Sett opp mapper
+ Sett opp mapper
Test tjenertilkobling
diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml
index 302e2a6df0f8..9e7225851c40 100644
--- a/src/main/res/values-nl/strings.xml
+++ b/src/main/res/values-nl/strings.xml
@@ -362,8 +362,8 @@ Kies er eentje van een provider.
%1$s kon niet worden gekopieerd naar de lokale map %2$s
Directe-uploadmap
- Lokale map
- Externe map
+ Lokale map
+ Externe map
Gebruik submappen
Opslaan in submappen, gebaseerd op jaar en maand
@@ -554,7 +554,7 @@ Kies er eentje van een provider.
Zoeken
Dit is een Nextcloud-optie, gelieve te updaten.
Meer weten
- Automatisch uploaden
+ Automatisch uploaden
Meedoen
Help bij testen
Bug gevonden? Rare dingen?
@@ -571,12 +571,12 @@ Kies er eentje van een provider.
Verplaats naar …
Kopieer naar …
Kies map …
- Mappen laden …
- Geen mediamappen gevonden.
- Voorkeuren voor automatisch uploaden
- Instellingen
- Direct uploaden is helemaal herzien. Bekijk het hoofdmenu en herconfigureer je auto-uploadfunctie. Onze excuses voor het ongemak.\n\nVeel plezier met de nieuwe en meer uitgebreide auto-upload-mogelijkheden!
- Voor %1$s
+ Mappen laden …
+ Geen mediamappen gevonden.
+ Voorkeuren voor automatisch uploaden
+ Instellingen
+ Direct uploaden is helemaal herzien. Bekijk het hoofdmenu en herconfigureer je auto-uploadfunctie. Onze excuses voor het ongemak.\n\nVeel plezier met de nieuwe en meer uitgebreide auto-upload-mogelijkheden!
+ Voor %1$s
- %d geselecteerd
- %d geselecteerd
@@ -659,7 +659,7 @@ Kies er eentje van een provider.
Privacy
Bestand niet gevonden!
- Mappen instellen
+ Mappen instellen
Test server verbinding
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index 5fdae4f81ce4..96827bb18b8d 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -357,8 +357,8 @@
%1$s nie może zostać skopiowany do lokalnego folderu %2$s
Folder natychmiastowego wysyłania
- Folder lokalny
- Folder zdalny
+ Folder lokalny
+ Folder zdalny
Używaj podfolderów
Zapisz w podfolderach opartych na roku oraz miesiącu
@@ -539,7 +539,7 @@
Wyszukaj
Ta funkcja jest dostępna w Nextcloud, prosimy wykonać aktualizację
Dowiedz się więcej
- Automatyczne przesyłanie
+ Automatyczne przesyłanie
Wspieraj
Pomóż nam testować
Znaleziono błąd? Jest coś dziwnego?
@@ -551,12 +551,12 @@
Przenieś do…
Skopiuj do…
Wybierz folder…
- Ładowanie folderów…
- Nie znaleziono folderów multimedialnych.
- Preferencje automatycznego wysyłania
- Ustawienia
- Natychmiastowe wysyłanie zostało kompletnie zmienione. Proszę sprawdzić główne menu i zrekonfigurować automatyczne wysyłanie. Przepraszamy za niedogodności.\n\nCiesz się z nowych i rozbudowanych możliwości automatycznego wysyłania!
- Dla %1$s
+ Ładowanie folderów…
+ Nie znaleziono folderów multimedialnych.
+ Preferencje automatycznego wysyłania
+ Ustawienia
+ Natychmiastowe wysyłanie zostało kompletnie zmienione. Proszę sprawdzić główne menu i zrekonfigurować automatyczne wysyłanie. Przepraszamy za niedogodności.\n\nCiesz się z nowych i rozbudowanych możliwości automatycznego wysyłania!
+ Dla %1$s
- %d zaznaczony
- %d zaznaczone
@@ -641,6 +641,6 @@
Prywatność
Nie odnaleziono pliku
- Skonfiguruj foldery
+ Skonfiguruj foldery
diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml
index 6444026241d4..534ea5f73b15 100644
--- a/src/main/res/values-pt-rBR/strings.xml
+++ b/src/main/res/values-pt-rBR/strings.xml
@@ -362,8 +362,8 @@
%1$s não pôde ser copiado para pasta local %2$s
Pasta de envio automático
- Pasta local
- Pasta remota
+ Pasta local
+ Pasta remota
Usar subpastas
Armazena em subpastas baseado no ano e mês
@@ -557,7 +557,7 @@
Pesquisar
Este é um recurso do Nextcloud. Por favor, atualize.
Saiba mais
- Envio automático
+ Envio automático
Participar
Ajuda para teste
Encontrou um erro? Comentários?
@@ -577,12 +577,12 @@
Mover para…
Copiar para…
Escolha a pasta…
- Carregando pastas…
- Nenhuma pasta de mídia encontrada.
- Preferências do auto envio
- Configurações
- O envio automático foi completamente renovado. Reconfigure-o dentro do menu principal.\n\nCurta o novo e estendido envio automático.
- Para %1$s
+ Carregando pastas…
+ Nenhuma pasta de mídia encontrada.
+ Preferências do auto envio
+ Configurações
+ O envio automático foi completamente renovado. Reconfigure-o dentro do menu principal.\n\nCurta o novo e estendido envio automático.
+ Para %1$s
- %d selecionado
- %d selecionados
@@ -665,7 +665,7 @@
Privacidade
Arquivo não encontrado!
- Configurar pastas
+ Configurar pastas
Teste de conexão ao servidor
diff --git a/src/main/res/values-pt-rPT/strings.xml b/src/main/res/values-pt-rPT/strings.xml
index da15c58a91c5..f3606c454107 100644
--- a/src/main/res/values-pt-rPT/strings.xml
+++ b/src/main/res/values-pt-rPT/strings.xml
@@ -348,10 +348,16 @@
Quer realmente remover os itens selecionados e os seus conteúdos?
Procura
Conheça melhor
- Carregar automaticamente
+ Carregar automaticamente
Participe
- Dossiês multimédia não encontrados
- Parametros
+ Ajude-nos a testar
+ Encontrou um erro? Algo está a funcionar estranhamente?
+ Reportar um problema no Github
+ Interessado em nos ajudar a testar a próxima versão?
+ Dossiês multimédia não encontrados
+ Carregar preferências automaticamente
+ Parametros
+ Introduza o nome e tipo de ficheiro a ser carregado
Nome do ficheiro
Tipo de ficheiro
Atalhos(%s) de Internet
diff --git a/src/main/res/values-ro/strings.xml b/src/main/res/values-ro/strings.xml
index 9a85fdf4461a..4dd0a8b430e4 100644
--- a/src/main/res/values-ro/strings.xml
+++ b/src/main/res/values-ro/strings.xml
@@ -256,8 +256,8 @@
Previzualizare imagine
%1$s nu a putut fi copiat in dosarul local %2$s
Dosar pentru încărcare instantă
- Dosar local
- Dosar la distanță
+ Dosar local
+ Dosar la distanță
Folosește subdosare
Stocați in subdosar bazat pe an și lună
@@ -392,17 +392,19 @@
Caută
Aceasta este o funcționalitate Nextcloud, vă rugăm să actulizați aplicația.
Află mai mult
- Încărcare automată
+ Încărcare automată
Participă
Candidatul pentru lansare
Contribuie în mod activ
Mută în…
Copiază în…
Alege dosar…
- Încărcare dosare…
- Nu au fost găsite dosare media.
- Setări
- Pentru %1$s
+ Încărcare dosare…
+ Nu au fost găsite dosare media.
+ Preferințe pentru încărcare automată
+ Setări
+ Funcționalitatea de încărcare automată a fost refăcută complet. Vă rugăm să accesați meniul principal și să refaceți setările de încărcare automată. Ne cerem scuze pentru inconveniență.\n\nBucură-te de noile capabilități extinse ale funcției de încărcare automată!
+ Pentru %1$s
- %d selectat
- %d selectate
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index fb213f8a0fd4..b429833710d6 100644
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -364,8 +364,8 @@
%1$s невозможно скопировать в локальный каталог %2$s
Каталог для немедленной загрузки
- Локальный каталог
- Каталог на сервере
+ Локальный каталог
+ Каталог на сервере
Использовать подкаталоги
Хранить в них, учитывая год и месяц
@@ -559,7 +559,7 @@
Поиск
Это есть в новой версии Nextcloud, пожалуйста обновитесь
Узнать больше
- Автоматическая загрузка
+ Автоматическая загрузка
Участие
Помогите нам в тестировании
Нашли ошибку? Заметили необычное поведение программы?
@@ -579,12 +579,12 @@
Переместить в…
Копировать в…
Выберите каталог …
- Загрузка каталогов …
- Не найдены каталоги с медиа(файлами).
- Настройки автозагрузки
- Настройки
- Моментальная загрузка была полностью переделана. Используйте главное меню для перенастройки автоматической загрузки. Извините за неудобства.\n\nВам понравятся новые расширенные возможности автоматической загрузки!
- Для %1$s
+ Загрузка каталогов …
+ Не найдены каталоги с медиа(файлами).
+ Настройки автозагрузки
+ Настройки
+ Моментальная загрузка была полностью переделана. Используйте главное меню для перенастройки автоматической загрузки. Извините за неудобства.\n\nВам понравятся новые расширенные возможности автоматической загрузки!
+ Для %1$s
- %d выбран
- %d выбрано
@@ -669,7 +669,7 @@
Конфиденциальность
Файл не найден!
- Настроить каталоги
+ Настроить каталоги
Проверить соединение с сервером
diff --git a/src/main/res/values-sk-rSK/strings.xml b/src/main/res/values-sk-rSK/strings.xml
index abe0739d72e9..5ec46a8b7b20 100644
--- a/src/main/res/values-sk-rSK/strings.xml
+++ b/src/main/res/values-sk-rSK/strings.xml
@@ -247,8 +247,8 @@
Ukážka obrazu
%1$s nemožno skopírovať do lokálneho priečinka %2$s
Priečinok pre okamžité nahratie
- Miestny priečinok
- Vzdialený priečinok
+ Miestny priečinok
+ Vzdialený priečinok
Použi podpriečinky
Ulož v podpriečinkoch podľa roku a mesiaca
@@ -383,17 +383,19 @@
Hľadať
Toto je funkcia Nextcloudu, aktualizujte prosím.
Dozvedieť sa viac
- Automatické nahratie
+ Automatické nahratie
Zúčastniť sa
Release candidate
Aktívne prispievať
Presunúť do…
Kopírovať do…
Vybrať priečinok…
- Načítavanie priečinkov…
- Neboli nájdené žiadne multimediálne priečinky.
- Nastavenia
- Pre %1$s
+ Načítavanie priečinkov…
+ Neboli nájdené žiadne multimediálne priečinky.
+ Nastavenia automatického nahratia
+ Nastavenia
+ Okamžité nahrávanie bolo kompletne prepracované. Prezrite si prosím hlavné menu a znovu nastavte automatické nahrávanie. Ospravedlňujeme sa za vzniknuté problémy.\n\nUžite si nové, rozšírene možnosti automatického nahrávania!
+ Pre %1$s
- %d vybraný
- %d vybraných
diff --git a/src/main/res/values-sq/strings.xml b/src/main/res/values-sq/strings.xml
index 45576d20bfcc..9f53cc352063 100644
--- a/src/main/res/values-sq/strings.xml
+++ b/src/main/res/values-sq/strings.xml
@@ -362,8 +362,8 @@
%1$s s\’u kopjua dot te dosja vendore %2$s
Dosja e ngarkimit të çastit
- Dosje vendore
- Dosje e largët
+ Dosje vendore
+ Dosje e largët
Përdorni nëndosjet
Ruani në nëndosjet në bazë të vitit dhe muajit
@@ -557,7 +557,7 @@
Kërkoni
Ky është një tipar i Nextcloud-it, ju lutemi përditësojeni.
Mësoni më shumë
- Ngarkim automatik
+ Ngarkim automatik
Merni pjesë
Ndihmo duke testuar
Gjetet një defekt? Diçka është e çuditshme?
@@ -577,12 +577,12 @@
Levizni tek…
Kopjojeni tek…
Zgjidh dosjen…
- Duke ngarkuar dosjet…
- Nuk u gjetën dosje media
- Preferencat për ngarkimin automatik
- Konfigurimet
- Ngarkimi i menjëhershëm është ngritur plotësisht. Ju lutemi shikoni menun kryesore dhe ri-konfiguroni ngarkimet tuaja automatike. Ju kërkojmë ndjes për shqetësimin.\n\nShijojini aftësitë e reja dhe të zgjeruara të ngarkimit automatik.
- Për %1$s
+ Duke ngarkuar dosjet…
+ Nuk u gjetën dosje media
+ Ngarko automatikisht preferencat
+ Konfigurimet
+ Ngarkimi i menjëhershëm është ngritur plotësisht. Ju lutemi shikoni menun kryesore dhe ri-konfiguroni ngarkimet tuaja automatike. Ju kërkojmë ndjes për shqetësimin.\n\nShijojini aftësitë e reja dhe të zgjeruara të ngarkimit automatik.
+ Për %1$s
- %d të përzgjedhura
- %d të përzgjedhura
@@ -665,7 +665,7 @@
Privatësi
Skedari nuk u gjet!
- Konfiguro dosjet
+ Konfiguro dosjet
Testo lidhjen e serverit
diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml
index 7cdc6b909a1c..62b80a19d652 100644
--- a/src/main/res/values-sv/strings.xml
+++ b/src/main/res/values-sv/strings.xml
@@ -248,8 +248,8 @@
Förhandsvisa bild
%1$s kunde inte kopieras till %2$s lokal mapp
Sökväg för Automatisk uppladdning
- Lokal mapp
- Extern mapp
+ Lokal mapp
+ Extern mapp
Använd undermappar
Spara i undermappar baserat på år och månad
@@ -385,17 +385,19 @@
Sök
Detta är en Nextcloud funktion, vänligen uppdatera.
Lär dig mer
- Automatisk uppladdning
+ Automatisk uppladdning
Hjälp oss att bli bättre
Release candidate
Bidra aktivt
Fllytta till…
Kopiera till…
Välj mapp…
- Laddar mappar…
- Inga mediamappar hittades
- Inställningar
- Mapp på telefonen: %1$s
+ Laddar mappar…
+ Inga mediamappar hittades
+ Aktivera Automatisk uppladdning
+ Inställningar
+ Direktuppladdning heter numera Automatisk uppladdning och har blivit totalt omgjort. Vänligen se huvudmenyn för att konfigurera Automatisk uppladdning igen. Ledsen för besväret.\n\nNjut av de nya och förbättrade uppladdningsmöjligheterna!
+ Mapp på telefonen: %1$s
- %d vald
- %d vald
diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml
index 6daaa915de8e..46c6e06361cc 100644
--- a/src/main/res/values-tr/strings.xml
+++ b/src/main/res/values-tr/strings.xml
@@ -362,8 +362,8 @@
%1$s, %2$s yerel klasörüne kopyalanamadı
Anında yükleme klasörü
- Yerel klasör
- Uzak klasör
+ Yerel klasör
+ Uzak klasör
Alt klasörler kullanılsın
Yıla ve aya göre alt klasörlere kaydedilsin
@@ -557,7 +557,7 @@
Arama
Bu bir Nextcloud özelliğidir, lütfen güncelleyin.
Ayrıntılı bilgi alın
- Otomatik yükleme
+ Otomatik yükleme
Katkıda bulunun
Denememize yardımcı olun
Bir hata mı buldunuz? Bir gariplik mi var?
@@ -577,12 +577,12 @@
Taşı…
Kopyala…
Klasör seçin…
- Klasörler yükleniyor…
- Herhangi bir ortam klasörü bulunamadı.
- Otomatik yükleme ayarları
- Ayarlar
- Anında yükleme tamamen elden geçirildi. Lütfen ama menüye giderek otomatik yükleme ayarlarınızı yeniden yapın.\n\nYeni ve geliştirilmiş otomatik yükleme özellklerinin tadını çıkarın.
- %1$s için
+ Klasörler yükleniyor…
+ Herhangi bir ortam klasörü bulunamadı.
+ Otomatik yükleme ayarları
+ Ayarlar
+ Anında yükleme tamamen elden geçirildi. Lütfen ama menüye giderek otomatik yükleme ayarlarınızı yeniden yapın.\n\nYeni ve geliştirilmiş otomatik yükleme özellklerinin tadını çıkarın.
+ %1$s için
- %d seçilmiş
- %d seçilmiş
@@ -665,7 +665,7 @@
Gizlilik
Dosya bulunamadı!
- Klasör ayarları
+ Klasör ayarları
Sunucu bağlantısını sına
diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml
index dfa9eab1a24a..c93d31df97a1 100644
--- a/src/main/res/values-uk/strings.xml
+++ b/src/main/res/values-uk/strings.xml
@@ -334,9 +334,6 @@
Перемістити до…
Копіювати до…
Оберіть каталог…
- Завантаження каталогів…
- Налаштування
- Для %1$s
- %d обрано
- %d обрано
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 52c4586adc7d..a17c0f7be7a5 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -365,8 +365,8 @@
无法复制 %1$s 到本地目录 %2$s
实时上传文件夹
- 本地文件夹
- 远端文件夹
+ 本地文件夹
+ 远端文件夹
使用子文件夹
基于年和月存于子文件夹
@@ -560,7 +560,7 @@
搜索
这是一个Nextcloud的特征,请更新
学习更多
- 自动上传
+ 自动上传
参加
通过测试帮助
发现错误?细节?
@@ -580,12 +580,12 @@
转移到…
复制到
选择文件夹…
- 加载文件夹…
- 没有发现媒体文件夹
- 自动上传的首选项
- 设置
- 即时上传已完全重新整理。 从主菜单重新配置您的自动上传。\ n \ n请使用新的的和扩展的自动上传。
- 为%1$s
+ 加载文件夹…
+ 没有发现媒体文件夹
+ 自动上传的首选项
+ 设置
+ 即时上传已完全重新整理。 从主菜单重新配置您的自动上传。\ n \ n请使用新的的和扩展的自动上传。
+ 为%1$s
- %d被选择
@@ -667,7 +667,7 @@
隐私
文件未找到
- 配置文件夹
+ 配置文件夹
测试服务连接
diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml
index 364cbe4fc7a9..81cf17adcfd3 100644
--- a/src/main/res/values-zh-rTW/strings.xml
+++ b/src/main/res/values-zh-rTW/strings.xml
@@ -362,8 +362,6 @@
%1$s 無法被複製到本地資料夾 %2$s
即時上傳資料夾
- 本地資料夾
- 遠端資料夾
使用子資料夾
依據年月存在子資料夾內
@@ -558,7 +556,6 @@
搜尋
這是 Nextcloud 的功能,請更新
瞭解更多
- 自動上傳
參與
協助測試
發現問題或瑕疵?
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
index 14f140ef4d89..690a57806a18 100644
--- a/src/main/res/values/colors.xml
+++ b/src/main/res/values/colors.xml
@@ -27,11 +27,13 @@
#fafafa
#B2000000
@color/black
+ #ff888888
#eee
#DDDDDD
#EEEEEE
#00000000
#a0a0a0
+ #e53935
#757575
diff --git a/src/main/res/values/dims.xml b/src/main/res/values/dims.xml
index b544c2005869..a3556ead6caa 100644
--- a/src/main/res/values/dims.xml
+++ b/src/main/res/values/dims.xml
@@ -18,9 +18,6 @@
-->
- @dimen/standard_padding
- @dimen/standard_padding
- 260dp
140dp
56dp
@@ -71,25 +68,18 @@
14sp
12sp
2dp
- 2dp
12dp
20dp
15dp
40dp
240dp
- 15dp
- 30dp
16dip
100dp
2dp
16dp
- 22dp
32dp
12dp
64dp
- 16dip
- -4dip
- 40dp
200dp
20dp
12sp
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index d77634e709c0..abbebe0f1469 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -45,6 +45,7 @@
Passcode lock
Fingerprint lock
No fingerprints have been set up.
+ Expert mode
Show hidden files
Instant uploading of pictures
Upload pictures taken by camera instantly
@@ -80,6 +81,7 @@
Files
Connect
Upload
+ Choose
Choose upload folder
No account found
There are no %1$s accounts on your device. Please set up an account first.
@@ -98,6 +100,7 @@
Delete file from source folder
seconds ago
No files here
+ No folders here
Upload some content or sync with your devices.
Favorite some files or sync with your devices.
Files and folders you mark as favorites will show up here
@@ -105,6 +108,7 @@
Loading…
No app set up to handle this file type.
There are no files in this folder.
+ There are no further folders.
No results in this folder
No results
Nothing favorited yet
@@ -153,11 +157,14 @@
unknown
Unknown error
Pending
+ Delete
About
Change password
Remove account
Delete account %s with all local files?\n\nDeleting cannot be undone.
Create account
+ Avatar
+ Active user
Upload from …
Folder name
Uploading …
@@ -169,7 +176,7 @@
Upload failed, you need to log in again
Uploads
Current
- Failed (tap to retry)
+ Failed / Pending restart
Uploaded
Completed
Cancelled
@@ -363,8 +370,8 @@
%1$s could not be copied to %2$s local folder
Instant upload folder
- Local folder
- Remote folder
+ Local folder
+ Remote folder
Use subfolders
Store in subfolders based on year and month
@@ -536,10 +543,11 @@
Stop sharing
done
- New attempt failed
- Clear failed
+ Retry failed uploads
+ Clear failed uploads
Clear successful uploads
Clear finished uploads
+ Force rescan
Grid view
List view
@@ -554,12 +562,13 @@
Do you really want to remove the selected items?
Do you really want to remove the selected items and their contents?
Server in maintenance mode
+ Failed to lock the file
Awaiting charge
Search
This is a Nextcloud feature, please update.
Learn more
- Auto upload
+ Auto upload
Participate
Help by testing
Found a bug? Oddments?
@@ -582,13 +591,15 @@
<font color=\"%1$s\"><a href=\"%2$s\">CONTRIBUTING.md</a></font>
Move to…
Copy to…
- Choose folder…
- Loading folders…
- No media folders found.
- Preferences for auto uploading
- Settings
- Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading.
- For %1$s
+ Choose remote folder…
+ Choose local folder…
+ Loading folders…
+ No media folders found.
+ Preferences for auto uploading
+ Settings
+ Instant uploading has been revamped completely. Re-configure your auto upload from within the main menu.\n\nEnjoy the new and extended auto uploading.
+ For %1$s
+ +
+ Set up a custom folder
+ Create new custom folder setup
+ Configure folders
-
+
Test server connection
+ ,
diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml
index 6f9d60d1aa96..2cade420505a 100644
--- a/src/main/res/values/styles.xml
+++ b/src/main/res/values/styles.xml
@@ -116,7 +116,11 @@
+
+
+
\ No newline at end of file
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index b9791889ee15..73d07cbd1254 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -27,15 +27,15 @@
android:key="storage_path"/>
+ android:title="@string/drawer_synced_folders"
+ android:key="synced_folders_category">
+ android:title="@string/synced_folders_configure_folders"
+ android:id="@+id/synced_folders_configure_folders"
+ android:key="synced_folders_configure_folders"/>
@@ -102,6 +102,9 @@
+
diff --git a/src/modified/java/com/owncloud/android/utils/PushUtils.java b/src/modified/java/com/owncloud/android/utils/PushUtils.java
index 0fd4c7e7e473..dbb58f5a59b1 100644
--- a/src/modified/java/com/owncloud/android/utils/PushUtils.java
+++ b/src/modified/java/com/owncloud/android/utils/PushUtils.java
@@ -167,7 +167,7 @@ private static void deleteRegistrationForAccount(Account account) {
remoteOperationResult = unregisterAccountDeviceForProxyOperation.execute(mClient);
if (remoteOperationResult.isSuccess()) {
- arbitraryDataProvider.deleteKeyForAccount(account, KEY_PUSH);
+ arbitraryDataProvider.deleteKeyForAccount(account.name, KEY_PUSH);
}
}
}
@@ -244,7 +244,7 @@ public static void pushRegistrationToServer() {
PushConfigurationState pushArbitraryData = new PushConfigurationState(token,
pushResponse.getDeviceIdentifier(), pushResponse.getSignature(),
pushResponse.getPublicKey(), false);
- arbitraryDataProvider.storeOrUpdateKeyValue(account, KEY_PUSH,
+ arbitraryDataProvider.storeOrUpdateKeyValue(account.name, KEY_PUSH,
gson.toJson(pushArbitraryData));
}
}