diff --git a/README.md b/README.md index a3267cb..3c14284 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![API](https://img.shields.io/badge/API-14%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=14) -[![jitPack](https://jitpack.io/v/jaiselrahman/FilePicker.svg)](https://jitpack.io/#jaiselrahman/FilePicker) -[![Monthly Downloads](https://jitpack.io/v/jaiselrahman/FilePicker/month.svg)](https://jitpack.io/#jaiselrahman/FilePicker) -[![Weekly Downloads](https://jitpack.io/v/jaiselrahman/FilePicker/week.svg)](https://jitpack.io/#jaiselrahman/FilePicker) +[![](https://jitpack.io/v/fuzhengyin/FilePicker.svg)](https://jitpack.io/#fuzhengyin/FilePicker) +[![Monthly Downloads](https://jitpack.io/v/jaiselrahman/FilePicker/month.svg)](https://jitpack.io/#fuzhengyin/FilePicker) +[![Weekly Downloads](https://jitpack.io/v/jaiselrahman/FilePicker/week.svg)](https://jitpack.io/#fuzhengyin/FilePicker) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-FilePicker-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/7002) A FilePicker library for Android for selecting multiple types of files and also to capture Images and Videos. diff --git a/app/src/main/java/com/jaiselrahman/filepickersample/MainActivity.java b/app/src/main/java/com/jaiselrahman/filepickersample/MainActivity.java index 2ba37e5..41b88f8 100644 --- a/app/src/main/java/com/jaiselrahman/filepickersample/MainActivity.java +++ b/app/src/main/java/com/jaiselrahman/filepickersample/MainActivity.java @@ -107,8 +107,11 @@ public void onClick(View v) { .setCheckPermission(true) .setShowImages(false) .setShowVideos(false) + .setIgnoreHiddenFile(false) + .setIgnoreNoMedia(false) .setShowAudios(true) .setSingleChoiceMode(true) + .setSuffixes("mp3") .setSelectedMediaFile(file) .setTitle("Select an audio") .build()); diff --git a/filepicker/src/main/java/com/jaiselrahman/filepicker/activity/FilePickerActivity.java b/filepicker/src/main/java/com/jaiselrahman/filepicker/activity/FilePickerActivity.java index 443a47e..a619110 100644 --- a/filepicker/src/main/java/com/jaiselrahman/filepicker/activity/FilePickerActivity.java +++ b/filepicker/src/main/java/com/jaiselrahman/filepicker/activity/FilePickerActivity.java @@ -28,6 +28,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.webkit.MimeTypeMap; @@ -81,7 +82,7 @@ public class FilePickerActivity extends AppCompatActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + long current = System.currentTimeMillis(); configs = getIntent().getParcelableExtra(CONFIGS); if (configs == null) { configs = new Configurations.Builder().build(); @@ -169,6 +170,7 @@ public boolean isAutoMeasureEnabled() { if (maxCount > 0) { setTitle(getResources().getString(title_res, fileGalleryAdapter.getSelectedItemCount(), maxCount, title)); } + Log.i(TAG, "onCreate: ms:"+(System.currentTimeMillis() - current)); } private boolean useDocumentUi() { @@ -191,6 +193,7 @@ public void onChanged(PagedList mediaFiles) { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + Log.d(TAG, "onRequestPermissionsResult() called with: requestCode = [" + requestCode + "], permissions = [" + permissions + "], grantResults = [" + grantResults + "]"); if (requestCode == REQUEST_WRITE_PERMISSION) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { loadFiles(); @@ -212,6 +215,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis @SuppressLint("NewApi") @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]"); if (requestCode == FileGalleryAdapter.CAPTURE_IMAGE_VIDEO) { if (resultCode == RESULT_OK) { String path = fileGalleryAdapter.getLastCapturedFile(); diff --git a/filepicker/src/main/java/com/jaiselrahman/filepicker/config/Configurations.java b/filepicker/src/main/java/com/jaiselrahman/filepicker/config/Configurations.java index e62e83b..fe2ef6b 100644 --- a/filepicker/src/main/java/com/jaiselrahman/filepicker/config/Configurations.java +++ b/filepicker/src/main/java/com/jaiselrahman/filepicker/config/Configurations.java @@ -40,8 +40,8 @@ public Configurations[] newArray(int size) { } }; - public static int PAGE_SIZE = 120; - public static int PREFETCH_DISTANCE = 40; + public static int PAGE_SIZE = 30; + public static int PREFETCH_DISTANCE = 10; private final boolean imageCaptureEnabled; private final boolean videoCaptureEnabled; @@ -345,6 +345,11 @@ public Builder setRootPath(String rootPath) { return this; } + /** + * 根据后缀名过滤 + * @param suffixes 不需要在后缀名前面添加`.` 内部会自动添加 + * @return + */ public Builder setSuffixes(String... suffixes) { this.suffixes = suffixes; return this; diff --git a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/DirViewModel.java b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/DirViewModel.java index 488ef24..792ac73 100644 --- a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/DirViewModel.java +++ b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/DirViewModel.java @@ -51,8 +51,8 @@ public void refresh() { } public static class Factory extends ViewModelProvider.NewInstanceFactory { - private ContentResolver contentResolver; - private Configurations configs; + private final ContentResolver contentResolver; + private final Configurations configs; public Factory(ContentResolver contentResolver, Configurations configs) { this.contentResolver = contentResolver; diff --git a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileDataSource.java b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileDataSource.java index 2f34bc7..6124154 100644 --- a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileDataSource.java +++ b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileDataSource.java @@ -20,9 +20,12 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.provider.MediaStore; +import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.core.content.ContentResolverCompat; import androidx.paging.DataSource; import androidx.paging.PositionalDataSource; @@ -47,14 +50,17 @@ public class MediaFileDataSource extends PositionalDataSource { - private Configurations configs; - private ContentResolver contentResolver; + private final Configurations configs; + private final ContentResolver contentResolver; - private String[] projection; - private String sortOrder; - private String selection; - private String[] selectionArgs; - private Uri uri; + private final String[] projection; + private final String sortOrder; + + private final String sortColumn; + private final int sortDirection; + private final String selection; + private final String[] selectionArgs; + private final Uri uri; private MediaFileDataSource(ContentResolver contentResolver, Uri uri, @NonNull Configurations configs, Long dirId) { this.contentResolver = contentResolver; @@ -114,6 +120,18 @@ private MediaFileDataSource(ContentResolver contentResolver, Uri uri, @NonNull C selectionBuilder.append(") and "); } + if (configs.isShowAudios()) { + String[] suffixes = configs.getSuffixes(); + if (suffixes.length > 0) { + selectionBuilder.append("("); + for (String suffix : suffixes) { + selectionBuilder.append(DATA).append(" like '%.").append(suffix).append("' or "); + } + selectionBuilder.delete(selectionBuilder.length()-4, selectionBuilder.length()); + selectionBuilder.append(") AND "); + } + } + if (configs.isSkipZeroSizeFiles()) { selectionBuilder.append(SIZE).append(" > 0 "); } @@ -127,7 +145,6 @@ private MediaFileDataSource(ContentResolver contentResolver, Uri uri, @NonNull C if (canUseAlbumId(configs)) { projection.add(MediaStore.Audio.AudioColumns.ALBUM_ID); } - List folders = getFoldersToIgnore(contentResolver, configs); if (folders.size() > 0) { selectionBuilder.append(" and(").append(DATA).append(" NOT LIKE ? "); @@ -139,11 +156,13 @@ private MediaFileDataSource(ContentResolver contentResolver, Uri uri, @NonNull C } selectionBuilder.append(")"); } - this.projection = projection.toArray(new String[0]); + this.sortColumn = DATE_ADDED; this.sortOrder = DATE_ADDED + " DESC"; + this.sortDirection =ContentResolver.QUERY_SORT_DIRECTION_DESCENDING; this.selection = selectionBuilder.toString(); this.selectionArgs = selectionArgs.toArray(new String[0]); + } @Override @@ -155,8 +174,25 @@ public void loadInitial(@NonNull LoadInitialParams params, @NonNull LoadInitialC public void loadRange(@NonNull LoadRangeParams params, @NonNull LoadRangeCallback callback) { callback.onResult(getMediaFiles(params.startPosition, params.loadSize)); } - + @RequiresApi(api = Build.VERSION_CODES.O) + private Bundle create(int limit, int offset) { + Bundle bundle = new Bundle(); + bundle.putInt(ContentResolver.QUERY_ARG_LIMIT, limit); + bundle.putInt(ContentResolver.QUERY_ARG_OFFSET, offset); + if (sortColumn !=null && sortColumn.trim().length() != 0) { + bundle.putString(ContentResolver.QUERY_ARG_SORT_COLUMNS, sortColumn); + bundle.putInt(ContentResolver.QUERY_ARG_SORT_DIRECTION, sortDirection); + } + bundle.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, selection); + bundle.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs); + return bundle; + } private List getMediaFiles(int offset, int limit) { + Log.i("Fuzhengyin", "getMediaFiles: offset:"+offset+" limit:"+limit); + if (android.os.Build.VERSION.SDK_INT >= 30) { + Cursor query = contentResolver.query(uri, projection, create(limit, offset), null); + return MediaFileLoader.asMediaFiles(query, configs); + } Cursor data = ContentResolverCompat.query(contentResolver, uri, projection, selection, selectionArgs, sortOrder + " LIMIT " + limit + " OFFSET " + offset, null); @@ -176,6 +212,9 @@ private static boolean canUseMediaType(Configurations configs) { @NonNull private static List getFoldersToIgnore(ContentResolver contentResolver, Configurations configs) { + if (!configs.isIgnoreHiddenFile() && !configs.isIgnoreNoMediaDir() && configs.getIgnorePathMatchers() == null) { + return new ArrayList<>(); + } Uri uri = MediaStore.Files.getContentUri("external"); String[] projection = new String[]{DATA}; @@ -257,11 +296,11 @@ private static boolean isExcluded(String path, List ignoredPaths) { } public static class Factory extends DataSource.Factory { - private ContentResolver contentResolver; - private Configurations configs; - private Long dirId; + private final ContentResolver contentResolver; + private final Configurations configs; + private final Long dirId; - private Uri uri; + private final Uri uri; Factory(ContentResolver contentResolver, Configurations configs, Long dirId) { this.contentResolver = contentResolver; diff --git a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileLoader.java b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileLoader.java index ffe1fbb..92284ac 100644 --- a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileLoader.java +++ b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileLoader.java @@ -23,6 +23,7 @@ import android.os.Build; import android.provider.MediaStore; import android.text.TextUtils; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -81,6 +82,7 @@ static Uri getContentUri(Configurations configs) { } static List asMediaFiles(Cursor data, Configurations configs) { + long current = System.currentTimeMillis(); ArrayList mediaFiles = new ArrayList<>(data.getCount()); if (data.moveToFirst()) do { @@ -89,6 +91,7 @@ static List asMediaFiles(Cursor data, Configurations configs) { mediaFiles.add(mediaFile); } } while (data.moveToNext()); + Log.i("Fuzhengyin", "asMediaFiles: ms:"+(System.currentTimeMillis() - current)); return mediaFiles; } diff --git a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileViewModel.java b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileViewModel.java index c8518ee..7854afe 100644 --- a/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileViewModel.java +++ b/filepicker/src/main/java/com/jaiselrahman/filepicker/model/MediaFileViewModel.java @@ -29,10 +29,10 @@ import com.jaiselrahman.filepicker.config.Configurations; public class MediaFileViewModel extends ViewModel { - private ContentResolver contentResolver; + private final ContentResolver contentResolver; public LiveData> mediaFiles; - private ContentObserver contentObserver = new ContentObserver(null) { + private final ContentObserver contentObserver = new ContentObserver(null) { @Override public void onChange(boolean selfChange) { refresh(); @@ -69,9 +69,9 @@ public void refresh() { } public static class Factory extends ViewModelProvider.NewInstanceFactory { - private ContentResolver contentResolver; - private Configurations configs; - private Long dirId; + private final ContentResolver contentResolver; + private final Configurations configs; + private final Long dirId; public Factory(ContentResolver contentResolver, Configurations configs, Long dirId) { this.contentResolver = contentResolver;