diff --git a/app/build.gradle b/app/build.gradle index 5a12db5b8..ead5dfc30 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId 'com.seafile.seadroid2' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 112 - versionName "2.2.37" + versionCode 114 + versionName "2.2.39" multiDexEnabled true resValue "string", "authorities", applicationId + '.cameraupload.provider' resValue "string", "account_type", "com.seafile.seadroid2.account.api2" diff --git a/app/src/main/java/com/seafile/seadroid2/cameraupload/BucketsSelectionFragment.java b/app/src/main/java/com/seafile/seadroid2/cameraupload/BucketsSelectionFragment.java index 00cfc9727..39c325044 100644 --- a/app/src/main/java/com/seafile/seadroid2/cameraupload/BucketsSelectionFragment.java +++ b/app/src/main/java/com/seafile/seadroid2/cameraupload/BucketsSelectionFragment.java @@ -1,7 +1,9 @@ package com.seafile.seadroid2.cameraupload; import android.content.Context; +import android.graphics.Bitmap; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.support.v4.app.Fragment; @@ -21,8 +23,6 @@ import java.io.File; import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; /** @@ -31,44 +31,52 @@ public class BucketsSelectionFragment extends Fragment { private List buckets; - private List tempBuckets; private boolean[] selectedBuckets; private ImageAdapter imageAdapter; + private Bitmap[] thumbnails; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = getActivity().getLayoutInflater().inflate(R.layout.cuc_bucket_selection_layout, null); - tempBuckets = GalleryBucketUtils.getMediaBuckets(getActivity().getApplicationContext()); SettingsManager settingsManager = SettingsManager.instance(); List currentBucketList = settingsManager.getCameraUploadBucketList(); - LinkedHashSet bucketsSet = new LinkedHashSet<>(tempBuckets.size()); - bucketsSet.addAll(tempBuckets); - buckets = new ArrayList<>(bucketsSet.size()); - Iterator iterator = bucketsSet.iterator(); - while (iterator.hasNext()) { - GalleryBucketUtils.Bucket bucket = (GalleryBucketUtils.Bucket) iterator.next(); - buckets.add(bucket); - } + buckets = GalleryBucketUtils.getMediaBuckets(getActivity().getApplicationContext()); selectedBuckets = new boolean[buckets.size()]; - for (int i = 0; i < buckets.size(); i++) { - GalleryBucketUtils.Bucket b = buckets.get(i); - if (b.isImages != null && b.isImages.equals(GalleryBucketUtils.IMAGES)) { - Uri image_uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, b.imageId); - String image_path = Utils.getRealPathFromURI(SeadroidApplication.getAppContext(), image_uri, "images"); - b.imagePath = image_path; - } else { - Uri video_uri = Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, b.videoId); - String videoPath = Utils.getRealPathFromURI(SeadroidApplication.getAppContext(), video_uri, "video"); - b.videoPath = videoPath; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + thumbnails = new Bitmap[buckets.size()]; + for (int i = 0; i < buckets.size(); i++) { + GalleryBucketUtils.Bucket b = buckets.get(i); + if (b.image_id > 0) { + thumbnails[i] = MediaStore.Images.Thumbnails.getThumbnail( + getActivity().getApplicationContext().getContentResolver(), b.image_id, + MediaStore.Images.Thumbnails.MINI_KIND, null); + } + if (currentBucketList.size() > 0) + selectedBuckets[i] = currentBucketList.contains(b.id); + else + selectedBuckets[i] = b.isCameraBucket; } + } else { + for (int i = 0; i < this.buckets.size(); i++) { + GalleryBucketUtils.Bucket b = this.buckets.get(i); + if (b.isImages != null && b.isImages.equals(GalleryBucketUtils.IMAGES)) { + Uri image_uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, b.imageId); + String image_path = Utils.getRealPathFromURI(SeadroidApplication.getAppContext(), image_uri, "images"); + b.imagePath = image_path; + } else { + Uri video_uri = Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, b.videoId); + String videoPath = Utils.getRealPathFromURI(SeadroidApplication.getAppContext(), video_uri, "video"); + b.videoPath = videoPath; + } - // if the user has previously selected buckets, mark these. - // otherwise, select the ones that will be auto-guessed. - if (currentBucketList.size() > 0) - selectedBuckets[i] = currentBucketList.contains(b.id); - else - selectedBuckets[i] = b.isCameraBucket; + // if the user has previously selected buckets, mark these. + // otherwise, select the ones that will be auto-guessed. + if (currentBucketList.size() > 0) + selectedBuckets[i] = currentBucketList.contains(b.id); + else + selectedBuckets[i] = b.isCameraBucket; + } } GridView imagegrid = (GridView) rootView.findViewById(R.id.cuc_bucket_selection_grid); @@ -147,12 +155,15 @@ public void onClick(View v) { holder.marking.setBackgroundResource(R.drawable.checkbox_unchecked); } }); - if (buckets.get(position).isImages != null && buckets.get(position).isImages.equals(GalleryBucketUtils.IMAGES)) { - GlideApp.with(getActivity()).load(buckets.get(position).imagePath).into(holder.imageview); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + holder.imageview.setImageBitmap(thumbnails[position]); } else { - GlideApp.with(getActivity()).load(Uri.fromFile(new File(buckets.get(position).videoPath))).into(holder.imageview); + if (buckets.get(position).isImages != null && buckets.get(position).isImages.equals(GalleryBucketUtils.IMAGES)) { + GlideApp.with(getActivity()).load(buckets.get(position).imagePath).into(holder.imageview); + } else { + GlideApp.with(getActivity()).load(Uri.fromFile(new File(buckets.get(position).videoPath))).into(holder.imageview); + } } - if (selectedBuckets[position]) holder.marking.setBackgroundResource(R.drawable.checkbox_checked); else diff --git a/app/src/main/java/com/seafile/seadroid2/cameraupload/CameraSyncAdapter.java b/app/src/main/java/com/seafile/seadroid2/cameraupload/CameraSyncAdapter.java index 61ed01d19..d635705b3 100644 --- a/app/src/main/java/com/seafile/seadroid2/cameraupload/CameraSyncAdapter.java +++ b/app/src/main/java/com/seafile/seadroid2/cameraupload/CameraSyncAdapter.java @@ -379,8 +379,8 @@ private void uploadImages(SyncResult syncResult, DataManager dataManager) throws if (bucketList.size() > 0) { selectedBuckets = bucketList; } else { - List allBuckets = GalleryBucketUtils.getMediaBuckets(getContext()); - for (GalleryBucketUtils.Bucket bucket: allBuckets) { + List allBuckets = GalleryBucketUtils.getMediaBuckets(SeadroidApplication.getAppContext()); + for (GalleryBucketUtils.Bucket bucket : allBuckets) { if (bucket.isCameraBucket) selectedBuckets.add(bucket.id); } @@ -438,10 +438,11 @@ private void uploadVideos(SyncResult syncResult, DataManager dataManager) throws if (bucketList.size() > 0) { selectedBuckets = bucketList; } else { - List allBuckets = GalleryBucketUtils.getMediaBuckets(getContext()); - for (GalleryBucketUtils.Bucket bucket: allBuckets) { + List allBuckets = GalleryBucketUtils.getMediaBuckets(SeadroidApplication.getAppContext()); + for (GalleryBucketUtils.Bucket bucket : allBuckets) { if (bucket.isCameraBucket) selectedBuckets.add(bucket.id); + } } @@ -540,7 +541,7 @@ private void iterateCursor(SyncResult syncResult, DataManager dataManager, Curso // local file does not exist. some inconsistency in the Media Provider? Ignore and continue if (!file.exists()) { // Log.d(DEBUG_TAG, "Skipping media "+file+" because it doesn't exist"); - Utils.utilsLogInfo(true, "=====Skipping media " + file + " because it doesn't exist"); +// Utils.utilsLogInfo(true, "=====Skipping media " + file + " because it doesn't exist"); syncResult.stats.numSkippedEntries++; continue; } @@ -554,7 +555,7 @@ private void iterateCursor(SyncResult syncResult, DataManager dataManager, Curso if (dbHelper.isUploaded(file)) { // Log.d(DEBUG_TAG, "Skipping media " + file + " because we have uploaded it in the past."); -// Utils.utilsLogInfo(true, "=====Skipping media " + file + " because we have uploaded it in the past."); + Utils.utilsLogInfo(true, "=====Skipping media " + file + " because we have uploaded it in the past."); continue; } diff --git a/app/src/main/java/com/seafile/seadroid2/cameraupload/GalleryBucketUtils.java b/app/src/main/java/com/seafile/seadroid2/cameraupload/GalleryBucketUtils.java index 8039b7a50..24cff933e 100644 --- a/app/src/main/java/com/seafile/seadroid2/cameraupload/GalleryBucketUtils.java +++ b/app/src/main/java/com/seafile/seadroid2/cameraupload/GalleryBucketUtils.java @@ -3,9 +3,14 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.provider.MediaStore; +import com.seafile.seadroid2.data.StorageManager; + import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; /** @@ -43,6 +48,9 @@ public boolean equals(Object obj) { return false; Bucket a = (Bucket) obj; + if (a.name == null || name == null) + return false; + return a.name.equals(this.name); } @@ -61,8 +69,15 @@ public int hashCode() { * @return the list of buckets. */ public static List getMediaBuckets(Context context) { - List video = getVideoBuckets(context); - List image = getImageBuckets(context); + List video; + List image; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + video = getVideoBucketsBelowApi29(context); + image = getImageBucketsBelowApi29(context); + } else { + video = getVideoBuckets(context); + image = getImageBuckets(context); + } List merged = image; @@ -76,6 +91,109 @@ public static List getMediaBuckets(Context context) { return merged; } + private static List getVideoBucketsBelowApi29(Context context) { + Uri images = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + String[] projection = new String[]{ + MediaStore.Video.Media.BUCKET_ID, + MediaStore.Video.Media.BUCKET_DISPLAY_NAME, + MediaStore.Video.Media.DATA + }; + + String BUCKET_ORDER_BY = MediaStore.Video.Media.BUCKET_DISPLAY_NAME + " ASC"; + String BUCKET_GROUP_BY = "1) GROUP BY 1,(2"; + Cursor cursor = context.getContentResolver().query(images, + projection, // Which columns to return + BUCKET_GROUP_BY, // Which rows to return (all rows) + null, // Selection arguments (none) + BUCKET_ORDER_BY // Ordering + ); + + List buckets = new ArrayList(); + + if (cursor == null) { + return buckets; + } + + while (cursor.moveToNext()) { + int bucketIdColumnIndex = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID); + int bucketColumnIndex = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME); + int dataColumnIndex = cursor.getColumnIndex(MediaStore.Video.Media.DATA); + Bucket b = new Bucket(); + b.id = cursor.getString(bucketIdColumnIndex); + b.name = cursor.getString(bucketColumnIndex); + b.isCameraBucket = false; + if (b.name == null) { + continue; + } + for (String name : CAMERA_BUCKET_NAMES) { + if (b.name.equalsIgnoreCase(name)) { + b.isCameraBucket = true; + } + } + + // ignore buckets created by Seadroid + String file = cursor.getString(dataColumnIndex); + if (file == null || !file.startsWith(StorageManager.getInstance().getMediaDir().getAbsolutePath())) + buckets.add(b); + } + cursor.close(); + + return buckets; + } + + private static List getImageBucketsBelowApi29(Context context) { + Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + String[] projection = new String[]{ + MediaStore.Images.Media.BUCKET_ID, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Video.Media.DATA, + MediaStore.Images.Media._ID + }; + + String BUCKET_ORDER_BY = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " ASC"; + String BUCKET_GROUP_BY = "1) GROUP BY 1,(2"; + Cursor cursor = context.getContentResolver().query(images, + projection, // Which columns to return + BUCKET_GROUP_BY, // Which rows to return (all rows) + null, // Selection arguments (none) + BUCKET_ORDER_BY // Ordering + ); + + List buckets = new ArrayList(); + + if (cursor == null) { + return buckets; + } + + while (cursor.moveToNext()) { + int bucketIdColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID); + int bucketColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME); + int dataColumnIndex = cursor.getColumnIndex(MediaStore.Video.Media.DATA); + int idColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID); + Bucket b = new Bucket(); + b.id = cursor.getString(bucketIdColumnIndex); + b.name = cursor.getString(bucketColumnIndex); + b.image_id = cursor.getInt(idColumnIndex); + b.isCameraBucket = false; + if (b.name == null) { + continue; + } + for (String name : CAMERA_BUCKET_NAMES) { + if (b.name.equalsIgnoreCase(name)) { + b.isCameraBucket = true; + } + } + + // ignore buckets created by Seadroid + String file = cursor.getString(dataColumnIndex); + if (file == null || !file.startsWith(StorageManager.getInstance().getMediaDir().getAbsolutePath())) + buckets.add(b); + } + cursor.close(); + + return buckets; + } + private static List getVideoBuckets(Context context) { Uri images = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; String[] projection = new String[]{ @@ -109,6 +227,9 @@ private static List getVideoBuckets(Context context) { } b.isCameraBucket = false; + if (b.name == null) { + continue; + } for (String name : CAMERA_BUCKET_NAMES) { if (b.name.equalsIgnoreCase(name)) { b.isCameraBucket = true; @@ -117,8 +238,15 @@ private static List getVideoBuckets(Context context) { buckets.add(b); } cursor.close(); - - return buckets; + LinkedHashSet bucketsSet = new LinkedHashSet<>(buckets.size()); + bucketsSet.addAll(buckets); + List tempBuckets = new ArrayList<>(bucketsSet.size()); + Iterator iterator = bucketsSet.iterator(); + while (iterator.hasNext()) { + GalleryBucketUtils.Bucket bucket = (GalleryBucketUtils.Bucket) iterator.next(); + tempBuckets.add(bucket); + } + return tempBuckets; } private static List getImageBuckets(Context context) { @@ -156,6 +284,9 @@ private static List getImageBuckets(Context context) { b.isCameraBucket = false; b.isImages = GalleryBucketUtils.IMAGES; + if (b.name == null) { + continue; + } for (String name : CAMERA_BUCKET_NAMES) { if (b.name.equalsIgnoreCase(name)) { b.isCameraBucket = true; @@ -164,7 +295,14 @@ private static List getImageBuckets(Context context) { buckets.add(b); } cursor.close(); - - return buckets; + LinkedHashSet bucketsSet = new LinkedHashSet<>(buckets.size()); + bucketsSet.addAll(buckets); + List tempBuckets = new ArrayList<>(bucketsSet.size()); + Iterator iterator = bucketsSet.iterator(); + while (iterator.hasNext()) { + GalleryBucketUtils.Bucket bucket = (GalleryBucketUtils.Bucket) iterator.next(); + tempBuckets.add(bucket); + } + return tempBuckets; } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/seafile/seadroid2/util/Utils.java b/app/src/main/java/com/seafile/seadroid2/util/Utils.java index 79972e09e..adfae2ffe 100644 --- a/app/src/main/java/com/seafile/seadroid2/util/Utils.java +++ b/app/src/main/java/com/seafile/seadroid2/util/Utils.java @@ -989,8 +989,9 @@ public static void logPhoneModelInfo() { public static void utilsLogInfo(boolean b, String info) { if (b) { -// Log.d(DEBUG_TAG, info); SeafileLog.d(DEBUG_TAG, info); + } else { + Log.d(DEBUG_TAG, info); } } }