diff --git a/.drone.yml b/.drone.yml
index c262805f3528..b00a744da8e6 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -1,6 +1,6 @@
pipeline:
test:
- image: nextcloudci/android:android-7
+ image: nextcloudci/android:android-14
commands:
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI -c 20M
- emulator -avd test -no-window &
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e8c1a2842147..b13fa200a097 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -25,7 +25,7 @@
+ android:targetSdkVersion="25" />
disable + show info
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
+ // 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))) {
diff --git a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java
index a405e7ef65f9..294439c806c6 100644
--- a/src/com/owncloud/android/ui/activity/FolderSyncActivity.java
+++ b/src/com/owncloud/android/ui/activity/FolderSyncActivity.java
@@ -21,6 +21,7 @@
package com.owncloud.android.ui.activity;
+import android.accounts.Account;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -48,6 +49,7 @@
import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment;
import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -130,7 +132,16 @@ private void load(final int perFolderMediaItemLimit) {
public void run() {
final List mediaFolders = MediaProvider.getMediaFolders(getContentResolver(),
perFolderMediaItemLimit);
- syncFolderItems = sortSyncedFolderItems(mergeFolderData(mSyncedFolderProvider.getSyncedFolders(),
+ List syncedFolderArrayList = mSyncedFolderProvider.getSyncedFolders();
+ List currentAccountSyncedFoldersList = new ArrayList();
+ Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(FolderSyncActivity.this);
+ for (SyncedFolder syncedFolder : syncedFolderArrayList) {
+ if (syncedFolder.getAccount().equals(currentAccount.name)) {
+ currentAccountSyncedFoldersList.add(syncedFolder);
+ }
+ }
+
+ syncFolderItems = sortSyncedFolderItems(mergeFolderData(currentAccountSyncedFoldersList,
mediaFolders));
mHandler.post(new TimerTask() {
@@ -157,15 +168,22 @@ private List mergeFolderData(List syncedF
Map syncedFoldersMap = createSyncedFoldersMap(syncedFolders);
List result = new ArrayList<>();
+
for (MediaFolder mediaFolder : mediaFolders) {
if (syncedFoldersMap.containsKey(mediaFolder.absolutePath)) {
SyncedFolder syncedFolder = syncedFoldersMap.get(mediaFolder.absolutePath);
+ syncedFoldersMap.remove(mediaFolder.absolutePath);
result.add(createSyncedFolder(syncedFolder, mediaFolder));
} else {
result.add(createSyncedFolderFromMediaFolder(mediaFolder));
}
}
+ for (SyncedFolder syncedFolder : syncedFoldersMap.values()) {
+ SyncedFolderDisplayItem syncedFolderDisplayItem = createSyncedFolderWithoutMediaFolder(syncedFolder);
+ result.add(syncedFolderDisplayItem);
+ }
+
return result;
}
@@ -210,6 +228,21 @@ public int compare(SyncedFolderDisplayItem f1, SyncedFolderDisplayItem f2) {
return syncFolderItemList;
}
+ @NonNull
+ private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull SyncedFolder syncedFolder) {
+ return new SyncedFolderDisplayItem(
+ syncedFolder.getId(),
+ syncedFolder.getLocalPath(),
+ syncedFolder.getRemotePath(),
+ syncedFolder.getWifiOnly(),
+ syncedFolder.getChargingOnly(),
+ syncedFolder.getSubfolderByDate(),
+ syncedFolder.getAccount(),
+ syncedFolder.getUploadAction(),
+ syncedFolder.isEnabled(),
+ new File(syncedFolder.getLocalPath()).getName());
+ }
+
/**
* creates a SyncedFolderDisplayItem merging a {@link SyncedFolder} and a {@link MediaFolder} object instance.
*
@@ -273,7 +306,6 @@ private Map createSyncedFoldersMap(List sync
}
return result;
}
-
/**
* show/hide recycler view list or the empty message / progress info.
*
@@ -289,7 +321,7 @@ private void setListShown(boolean shown) {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- boolean result;
+ boolean result = true;
switch (item.getItemId()) {
case android.R.id.home: {
if (isDrawerOpen()) {
@@ -297,6 +329,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
} else {
openDrawer();
}
+ break;
}
default:
@@ -323,9 +356,13 @@ public void showFiles(boolean onDeviceOnly) {
@Override
public void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) {
if (syncedFolderDisplayItem.getId() > UNPERSISTED_ID) {
- mSyncedFolderProvider.updateFolderSyncEnabled(syncedFolderDisplayItem.getId(), syncedFolderDisplayItem.isEnabled());
+ mSyncedFolderProvider.updateFolderSyncEnabled(syncedFolderDisplayItem.getId(),
+ syncedFolderDisplayItem.isEnabled());
} else {
- mSyncedFolderProvider.storeFolderSync(syncedFolderDisplayItem);
+ long storedId = mSyncedFolderProvider.storeFolderSync(syncedFolderDisplayItem);
+ if (storedId != -1) {
+ syncedFolderDisplayItem.setId(storedId);
+ }
}
}
@@ -362,7 +399,11 @@ public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) {
if (syncedFolder.getId() == UNPERSISTED_ID) {
// newly set up folder sync config
- mSyncedFolderProvider.storeFolderSync(item);
+ long storedId = mSyncedFolderProvider.storeFolderSync(item);
+ if (storedId != -1) {
+ item.setId(storedId);
+ }
+
} else {
// existing synced folder setup to be updated
mSyncedFolderProvider.updateSyncFolder(item);
diff --git a/src/com/owncloud/android/ui/activity/Preferences.java b/src/com/owncloud/android/ui/activity/Preferences.java
index bda0ca12587c..8802c72c720d 100644
--- a/src/com/owncloud/android/ui/activity/Preferences.java
+++ b/src/com/owncloud/android/ui/activity/Preferences.java
@@ -368,8 +368,8 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
mPrefInstantUploadCategory = (PreferenceCategory) findPreference("instant_uploading_category");
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
- // Instant upload via preferences on pre Android Nougat
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ // Instant upload via preferences on pre Android Marshmallow
mPrefInstantUploadPath = findPreference("instant_upload_path");
if (mPrefInstantUploadPath != null) {
diff --git a/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java b/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java
index 47b1dbfe95c2..8c21374390d2 100644
--- a/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java
+++ b/src/com/owncloud/android/ui/adapter/FolderSyncAdapter.java
@@ -77,7 +77,11 @@ public int getSectionCount() {
@Override
public int getItemCount(int section) {
- return mSyncFolderItems.get(section).getFilePaths().size();
+ if (mSyncFolderItems.get(section).getFilePaths() != null) {
+ return mSyncFolderItems.get(section).getFilePaths().size();
+ } else {
+ return 1;
+ }
}
@Override
@@ -108,37 +112,44 @@ public void onClick(View v) {
@Override
public void onBindViewHolder(MainViewHolder holder, int section, int relativePosition, int absolutePosition) {
- File file = new File(mSyncFolderItems.get(section).getFilePaths().get(relativePosition));
+ if (mSyncFolderItems.get(section).getFilePaths() != null) {
+ File file = new File(mSyncFolderItems.get(section).getFilePaths().get(relativePosition));
- ThumbnailsCacheManager.MediaThumbnailGenerationTask task =
- new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image);
+ ThumbnailsCacheManager.MediaThumbnailGenerationTask task =
+ new ThumbnailsCacheManager.MediaThumbnailGenerationTask(holder.image);
- ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable =
- new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable(
- mContext.getResources(),
- ThumbnailsCacheManager.mDefaultImg,
- task
- );
- holder.image.setImageDrawable(asyncDrawable);
+ ThumbnailsCacheManager.AsyncMediaThumbnailDrawable asyncDrawable =
+ new ThumbnailsCacheManager.AsyncMediaThumbnailDrawable(
+ mContext.getResources(),
+ ThumbnailsCacheManager.mDefaultImg,
+ task
+ );
+ holder.image.setImageDrawable(asyncDrawable);
- task.execute(file);
+ task.execute(file);
- // set proper tag
- holder.image.setTag(file.hashCode());
+ // set proper tag
+ holder.image.setTag(file.hashCode());
- holder.itemView.setTag(relativePosition % mGridWidth);
+ holder.itemView.setTag(relativePosition % mGridWidth);
+
+ if (mSyncFolderItems.get(section).getNumberOfFiles() > mGridTotal && relativePosition >= mGridTotal - 1) {
+ holder.counterValue.setText(Long.toString(mSyncFolderItems.get(section).getNumberOfFiles() - mGridTotal));
+ holder.counterBar.setVisibility(View.VISIBLE);
+ holder.thumbnailDarkener.setVisibility(View.VISIBLE);
+ } else {
+ holder.counterBar.setVisibility(View.GONE);
+ holder.thumbnailDarkener.setVisibility(View.GONE);
+ }
- if (mSyncFolderItems.get(section).getNumberOfFiles() > mGridTotal && relativePosition >= mGridTotal - 1) {
- holder.counterValue.setText(Long.toString(mSyncFolderItems.get(section).getNumberOfFiles() - mGridTotal));
+ //holder.itemView.setTag(String.format(Locale.getDefault(), "%d:%d:%d", section, relativePos, absolutePos));
+ //holder.itemView.setOnClickListener(this);
+ } else {
+ holder.itemView.setTag(relativePosition % mGridWidth);
+ holder.counterValue.setText(Long.toString(0));
holder.counterBar.setVisibility(View.VISIBLE);
holder.thumbnailDarkener.setVisibility(View.VISIBLE);
- } else {
- holder.counterBar.setVisibility(View.GONE);
- holder.thumbnailDarkener.setVisibility(View.GONE);
}
-
- //holder.itemView.setTag(String.format(Locale.getDefault(), "%d:%d:%d", section, relativePos, absolutePos));
- //holder.itemView.setOnClickListener(this);
}
@Override
diff --git a/src/com/owncloud/android/utils/FileStorageUtils.java b/src/com/owncloud/android/utils/FileStorageUtils.java
index 1eec561edd01..fafb31f9d314 100644
--- a/src/com/owncloud/android/utils/FileStorageUtils.java
+++ b/src/com/owncloud/android/utils/FileStorageUtils.java
@@ -39,6 +39,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -47,6 +48,7 @@
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.TimeZone;
import java.util.Vector;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -62,6 +64,7 @@ public class FileStorageUtils {
public static final Integer SORT_NAME = 0;
public static final Integer SORT_DATE = 1;
public static final Integer SORT_SIZE = 2;
+ public static final String PATTERN_YYYY_MM = "yyyy/MM/";
public static Integer mSortOrder = SORT_NAME;
public static Boolean mSortAscending = true;
@@ -122,42 +125,70 @@ public static String getLogPath() {
* string is returned
*
* @param date: date in microseconds since 1st January 1970
- * @return
+ * @return string: yyyy/mm/
*/
- private static String getSubpathFromDate(long date) {
+ private static String getSubpathFromDate(long date, Locale currentLocale) {
if (date == 0) {
return "";
}
- try {
- SimpleDateFormat formatter = new SimpleDateFormat(
- "yyyy" + OCFile.PATH_SEPARATOR + "MM" + OCFile.PATH_SEPARATOR, Locale.ENGLISH);
- return formatter.format(new Date(date));
- }
- catch(RuntimeException ex) {
- Log_OC.w(TAG, "could not extract date from timestamp");
+
+ Date d = new Date(date);
+
+ DateFormat df = new SimpleDateFormat(PATTERN_YYYY_MM, currentLocale);
+ df.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()));
+
+ return df.format(d);
+ }
+
+ private static String getSubpathFromDate(long date) {
+ if (date == 0) {
return "";
}
+
+ Date d = new Date(date);
+
+ DateFormat df = new SimpleDateFormat(PATTERN_YYYY_MM);
+
+ return df.format(d);
}
/**
- * Returns the InstantUploadFilePath on the owncloud instance
+ * Returns the InstantUploadFilePath on the nextcloud instance
*
- * @param fileName
+ * @param fileName complete file name
* @param dateTaken: Time in milliseconds since 1970 when the picture was taken.
- * @return
+ * @return instantUpload path, eg. /Camera/2017/01/fileName
*/
- public static String getInstantUploadFilePath(String remotePath, String fileName, long dateTaken,
+ public static String getInstantUploadFilePath(Locale current,
+ String remotePath,
+ String fileName,
+ long dateTaken,
+ Boolean subfolderByDate) {
+ String subPath = "";
+ if (subfolderByDate) {
+ subPath = getSubpathFromDate(dateTaken, current);
+ }
+
+ return remotePath + OCFile.PATH_SEPARATOR + subPath + (fileName == null ? "" : fileName);
+ }
+
+ public static String getInstantUploadFilePath(String remotePath,
+ String fileName,
+ long dateTaken,
Boolean subfolderByDate) {
String subPath = "";
if (subfolderByDate) {
- subPath = getSubpathFromDate(dateTaken);
+ subPath = getSubpathFromDate(dateTaken);
}
+
return remotePath + OCFile.PATH_SEPARATOR + subPath + (fileName == null ? "" : fileName);
}
+
/**
- * Gets the composed path when video is or must be stored
- * @param context
+ * Gets the composed path when video is or must be stored.
+ *
+ * @param context app context
* @param fileName: video file name
* @return String: video file path composed
*/
@@ -169,8 +200,7 @@ public static String getInstantVideoUploadFilePath(Context context, String fileN
if (com.owncloud.android.db.PreferenceManager.instantVideoUploadPathUseSubfolders(context)) {
subPath = getSubpathFromDate(dateTaken);
}
- return uploadVideoPath + OCFile.PATH_SEPARATOR + subPath
- + (fileName == null ? "" : fileName);
+ return uploadVideoPath + subPath + (fileName == null ? "" : fileName);
}
public static String getParentPath(String remotePath) {
@@ -241,7 +271,9 @@ public static Vector sortOcFolder(Vector files){
}
/**
- * Sorts all filenames, regarding last user decision
+ * Sorts all filenames, regarding last user decision.
+ *
+ * @param files of files to sort
*/
public static File[] sortLocalFolder(File[] files){
switch (mSortOrder){
@@ -260,8 +292,9 @@ public static File[] sortLocalFolder(File[] files){
}
/**
- * Sorts list by Date
- * @param files
+ * Sorts list by Date.
+ *
+ * @param files list of files to sort
*/
public static Vector sortOCFilesByDate(Vector files){
final int multiplier = mSortAscending ? 1 : -1;
@@ -278,8 +311,9 @@ public int compare(OCFile o1, OCFile o2) {
}
/**
- * Sorts list by Date
- * @param filesArray
+ * Sorts list by Date.
+ *
+ * @param filesArray list of files to sort
*/
public static File[] sortLocalFilesByDate(File[] filesArray){
final int multiplier = mSortAscending ? 1 : -1;
@@ -299,7 +333,9 @@ public int compare(File o1, File o2) {
}
/**
- * Sorts list by Size
+ * Sorts list by Size.
+ *
+ * @param files list of files to sort
*/
public static Vector sortOCFilesBySize(Vector files){
final int multiplier = mSortAscending ? 1 : -1;
@@ -326,7 +362,9 @@ public int compare(OCFile o1, OCFile o2) {
}
/**
- * Sorts list by Size
+ * Sorts list by Size.
+ *
+ * @param filesArray list of files to sort
*/
public static File[] sortLocalFilesBySize(File[] filesArray) {
final int multiplier = mSortAscending ? 1 : -1;
@@ -356,8 +394,9 @@ public int compare(File o1, File o2) {
}
/**
- * Sorts list by Name
- * @param files files to sort
+ * Sorts list by Name.
+ *
+ * @param files files to sort
*/
@SuppressFBWarnings(value = "Bx")
public static Vector sortOCFilesByName(Vector files){
@@ -380,8 +419,9 @@ public int compare(OCFile o1, OCFile o2) {
}
/**
- * Sorts list by Name
- * @param filesArray files to sort
+ * Sorts list by Name.
+ *
+ * @param filesArray files to sort
*/
public static File[] sortLocalFilesByName(File[] filesArray) {
final int multiplier = mSortAscending ? 1 : -1;
@@ -407,8 +447,9 @@ public int compare(File o1, File o2) {
}
/**
- * Sorts list by Favourites
- * @param files files to sort
+ * Sorts list by Favourites.
+ *
+ * @param files files to sort
*/
public static Vector sortOCFilesByFavourite(Vector files){
Collections.sort(files, new Comparator() {
diff --git a/src/com/owncloud/android/utils/RecursiveFileObserver.java b/src/com/owncloud/android/utils/RecursiveFileObserver.java
deleted file mode 100644
index b482882c43f6..000000000000
--- a/src/com/owncloud/android/utils/RecursiveFileObserver.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * ownCloud Android client application
- *
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2015 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package com.owncloud.android.utils;
-
-import android.os.FileObserver;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Stack;
-
-public class RecursiveFileObserver extends FileObserver {
-
- private final List mObservers = new ArrayList<>();
- private boolean watching = false;
- private String mPath;
- private int mMask;
-
- public RecursiveFileObserver(String path) {
- this(path, ALL_EVENTS);
- }
-
- public RecursiveFileObserver(String path, int mask) {
- super(path, mask);
- mPath = path;
- mMask = mask;
- }
-
- @Override
- public void startWatching() {
- if (watching) {
- return;
- }
- watching = true;
- final Stack stack = new Stack();
- stack.push(mPath);
-
- while (!stack.empty()) {
- String parent = stack.pop();
- mObservers.add(new SingleFileObserver(parent, mMask));
- File path = new File(parent);
- File[] files = path.listFiles();
- if (files == null) {
- continue;
- }
- for (final File file : files) {
- if (file.isDirectory() && !file.getName().equals(".")
- && !file.getName().equals("..")) {
- stack.push(file.getPath());
- }
- }
- }
- for (int i = 0; i < mObservers.size(); i++) {
- mObservers.get(i).startWatching();
- }
- }
-
- @Override
- public void stopWatching() {
- if (!watching) {
- return;
- }
-
- for (int i = 0; i < mObservers.size(); ++i) {
- mObservers.get(i).stopWatching();
- }
- mObservers.clear();
- watching = false;
- }
-
- @Override
- public void onEvent(int event, String path) {
-
- }
-
- private class SingleFileObserver extends FileObserver {
- private String mPath;
-
- SingleFileObserver(String path, int mask) {
- super(path, mask);
- mPath = path;
- }
-
- @Override
- public void onEvent(int event, String path) {
- String newPath = mPath + "/" + path;
- RecursiveFileObserver.this.onEvent(event, newPath);
- }
-
- }
-}