diff --git a/build.gradle b/build.gradle
index e2920929c0..a9e46925fd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -118,11 +118,11 @@ android {
javaMaxHeapSize "4g"
}
- compileSdkVersion 28
+ compileSdkVersion 29
defaultConfig {
minSdkVersion 16
- targetSdkVersion 28
+ targetSdkVersion 29
// arguments to be passed to functional tests
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt
index 009bd2c17f..102c15d537 100644
--- a/scripts/analysis/findbugs-results.txt
+++ b/scripts/analysis/findbugs-results.txt
@@ -1 +1 @@
-407
\ No newline at end of file
+409
diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt
index 07b704560a..8a9ea1fc4c 100644
--- a/scripts/analysis/lint-results.txt
+++ b/scripts/analysis/lint-results.txt
@@ -1,2 +1,2 @@
DO NOT TOUCH; GENERATED BY DRONE
- Lint Report: 59 warnings
+ Lint Report: 73 warnings
diff --git a/src/main/java/com/owncloud/android/datamodel/MediaProvider.java b/src/main/java/com/owncloud/android/datamodel/MediaProvider.java
index 24eba0dd3e..49f31bb204 100644
--- a/src/main/java/com/owncloud/android/datamodel/MediaProvider.java
+++ b/src/main/java/com/owncloud/android/datamodel/MediaProvider.java
@@ -37,7 +37,9 @@ import com.owncloud.android.utils.ThemeUtils;
import java.io.File;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.annotation.Nullable;
@@ -51,11 +53,11 @@ public final class MediaProvider {
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 IMAGES_FILE_SELECTION = MediaStore.Images.Media.BUCKET_ID + "=";
- private static final String[] IMAGES_FOLDER_PROJECTION = {"Distinct " + MediaStore.Images.Media.BUCKET_ID,
+ private static final String[] IMAGES_FOLDER_PROJECTION = {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,
+ private static final String[] VIDEOS_FOLDER_PROJECTION = {MediaStore.Video.Media.BUCKET_ID,
MediaStore.Video.Media.BUCKET_DISPLAY_NAME};
private MediaProvider() {
@@ -86,28 +88,35 @@ public final class MediaProvider {
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));
+ Map uniqueFolders = new HashMap<>();
+ // since sdk 29 we have to manually distinct on bucket id
+ while (cursorFolders.moveToNext()) {
+ uniqueFolders.put(cursorFolders.getString(
+ cursorFolders.getColumnIndex(MediaStore.Images.Media.BUCKET_ID)),
+ cursorFolders.getString(
+ cursorFolders.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME))
+ );
+ }
+ cursorFolders.close();
+
+ for (Map.Entry folder : uniqueFolders.entrySet()) {
MediaFolder mediaFolder = new MediaFolder();
- folderName = cursorFolders.getString(cursorFolders.getColumnIndex(
- MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
+
mediaFolder.type = MediaFolderType.IMAGE;
- mediaFolder.folderName = folderName;
+ mediaFolder.folderName = folder.getValue();
mediaFolder.filePaths = new ArrayList<>();
// query images
cursorImages = contentResolver.query(
- IMAGES_MEDIA_URI,
- FILE_PROJECTION,
- IMAGES_FILE_SELECTION + folderId,
- null,
- fileSortOrder
+ IMAGES_MEDIA_URI,
+ FILE_PROJECTION,
+ IMAGES_FILE_SELECTION + folder.getKey(),
+ null,
+ fileSortOrder
);
Log.d(TAG, "Reading images for " + mediaFolder.folderName);
@@ -116,7 +125,7 @@ public final class MediaProvider {
while (cursorImages.moveToNext()) {
filePath = cursorImages.getString(cursorImages.getColumnIndexOrThrow(
- MediaStore.MediaColumns.DATA));
+ MediaStore.MediaColumns.DATA));
// check if valid path and file exists
if (isValidAndExistingFilePath(filePath)) {
@@ -131,11 +140,11 @@ public final class MediaProvider {
// count images
Cursor count = contentResolver.query(
- IMAGES_MEDIA_URI,
- FILE_PROJECTION,
- IMAGES_FILE_SELECTION + folderId,
- null,
- null);
+ IMAGES_MEDIA_URI,
+ FILE_PROJECTION,
+ IMAGES_FILE_SELECTION + folder.getKey(),
+ null,
+ null);
if (count != null) {
mediaFolder.numberOfFiles = count.getCount();
@@ -146,7 +155,6 @@ public final class MediaProvider {
}
}
}
- cursorFolders.close();
}
return mediaFolders;
@@ -203,31 +211,38 @@ public final class MediaProvider {
String fileSortOrder = MediaStore.Video.Media.DATE_TAKEN + " DESC LIMIT " + itemLimit;
Cursor cursorVideos;
- while (cursorFolders.moveToNext()) {
- String folderId = cursorFolders.getString(cursorFolders.getColumnIndex(MediaStore.Video.Media
- .BUCKET_ID));
+ Map uniqueFolders = new HashMap<>();
+ // since sdk 29 we have to manually distinct on bucket id
+ while (cursorFolders.moveToNext()) {
+ uniqueFolders.put(cursorFolders.getString(
+ cursorFolders.getColumnIndex(MediaStore.Video.Media.BUCKET_ID)),
+ cursorFolders.getString(
+ cursorFolders.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME))
+ );
+ }
+ cursorFolders.close();
+
+ for (Map.Entry folder : uniqueFolders.entrySet()) {
MediaFolder mediaFolder = new MediaFolder();
- folderName = cursorFolders.getString(cursorFolders.getColumnIndex(
- MediaStore.Video.Media.BUCKET_DISPLAY_NAME));
mediaFolder.type = MediaFolderType.VIDEO;
- mediaFolder.folderName = folderName;
+ mediaFolder.folderName = folder.getValue();
mediaFolder.filePaths = new ArrayList<>();
// query videos
cursorVideos = contentResolver.query(
- MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
- FILE_PROJECTION,
- MediaStore.Video.Media.BUCKET_ID + "=" + folderId,
- null,
- fileSortOrder);
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ FILE_PROJECTION,
+ MediaStore.Video.Media.BUCKET_ID + "=" + folder.getKey(),
+ null,
+ fileSortOrder);
Log.d(TAG, "Reading videos for " + mediaFolder.folderName);
if (cursorVideos != null) {
String filePath;
while (cursorVideos.moveToNext()) {
filePath = cursorVideos.getString(cursorVideos.getColumnIndexOrThrow(
- MediaStore.MediaColumns.DATA));
+ MediaStore.MediaColumns.DATA));
if (filePath != null) {
mediaFolder.filePaths.add(filePath);
@@ -241,11 +256,11 @@ public final class MediaProvider {
// count images
Cursor count = contentResolver.query(
- MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
- FILE_PROJECTION,
- MediaStore.Video.Media.BUCKET_ID + "=" + folderId,
- null,
- null);
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ FILE_PROJECTION,
+ MediaStore.Video.Media.BUCKET_ID + "=" + folder.getKey(),
+ null,
+ null);
if (count != null) {
mediaFolder.numberOfFiles = count.getCount();