Skip to content

Commit f7acf91

Browse files
Added support for Android 13
1 parent 5002b8a commit f7acf91

File tree

10 files changed

+292
-68
lines changed

10 files changed

+292
-68
lines changed

Readme.md

+18-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Add it in your root build.gradle at the end of repositories:
4343
Step 2. Add the dependency
4444

4545
dependencies {
46-
implementation 'com.github.TutorialsAndroid:FilePicker:v8.0.19'
46+
implementation 'com.github.TutorialsAndroid:FilePicker:v9.0.0'
4747
}
4848

4949
### Usage
@@ -84,7 +84,7 @@ Step 2. Add the dependency
8484
3. Next create an instance of `FilePickerDialog`, and pass `Context` and `DialogProperties` references as parameters. Optional: You can change the title of dialog. Default is current directory name. Set the positive button string. Default is Select. Set the negative button string. Defalut is Cancel.
8585

8686
```java
87-
FilePickerDialog dialog = new FilePickerDialog(MainActivity.this,properties);
87+
FilePickerDialog dialog = new FilePickerDialog(MainActivity.this, MainActivity.this,properties);
8888
dialog.setTitle("Select a File");
8989
```
9090

@@ -125,6 +125,22 @@ Marshmallow and above requests for the permission on runtime. You should overrid
125125
}
126126
```
127127

128+
### Android13 and Above Instructions:
129+
If your app targets Android 13 or higher and needs to access media files that other apps have created, you must request one or more of the following granular media permissions instead of the ```READ_EXTERNAL_STORAGE permission```:
130+
As of Android 13 and above you can only browse and select Images,Videos and Audio files only. This library is still in development and I'm looking for contributors to make this library more better
131+
```
132+
Type of media | Permission to request
133+
134+
Images and photos | READ_MEDIA_IMAGES
135+
Videos | READ_MEDIA_VIDEO
136+
Audio files | READ_MEDIA_AUDIO
137+
```
138+
Before you access another app's media files, verify that the user has granted the appropriate granular media permissions to your app.
139+
140+
If you request both the ```READ_MEDIA_IMAGES``` permission and the ```READ_MEDIA_VIDEO``` permission at the same time, only one system permission dialog appears.
141+
142+
If your app was previously granted the ```READ_EXTERNAL_STORAGE``` permission, then any requested ```READ_MEDIA_*``` permissions are granted automatically when upgrading.
143+
128144
That's It. You are good to proceed further.
129145

130146

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
jcenter()
77
}
88
dependencies {
9-
classpath 'com.android.tools.build:gradle:7.1.2'
9+
classpath 'com.android.tools.build:gradle:8.1.1'
1010
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
1111

1212
// NOTE: Do not place your application dependencies here; they belong

gradle/wrapper/gradle-wrapper.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip

library/build.gradle

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
apply plugin: 'com.android.library'
2-
3-
//apply plugin: 'com.github.dcendents.android-maven'
42
group='com.github.TutorialsAndroid'
53

64
android {
7-
compileSdkVersion 31
5+
compileSdk 34
86

97
defaultConfig {
108
minSdkVersion 19
11-
targetSdkVersion 31
9+
targetSdkVersion 34
1210
}
1311
buildTypes {
1412
release {
1513
minifyEnabled false
1614
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
1715
}
1816
}
19-
lintOptions {
17+
namespace 'com.developer.filepicker'
18+
lint {
2019
abortOnError false
2120
}
2221
}

library/src/main/AndroidManifest.xml

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
<manifest
2-
xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="com.developer.filepicker">
4-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
5-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2+
xmlns:android="http://schemas.android.com/apk/res/android">
3+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
4+
android:maxSdkVersion="32" />
5+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
6+
android:maxSdkVersion="32" />
7+
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
8+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
9+
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
10+
<!-- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>-->
611
</manifest>

library/src/main/java/com/developer/filepicker/utils/Utility.java

+22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.developer.filepicker.utils;
22

3+
import android.Manifest;
4+
import android.app.Activity;
35
import android.content.Context;
46
import android.content.pm.PackageManager;
7+
import android.os.Build;
58

69
import com.developer.filepicker.model.FileListItem;
710

@@ -15,6 +18,8 @@
1518
*/
1619
public class Utility {
1720

21+
private static final int REQUEST_MEDIA_PERMISSIONS = 456;
22+
1823
public static boolean checkStorageAccessPermissions(Context context) {
1924
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
2025
String permission = "android.permission.READ_EXTERNAL_STORAGE";
@@ -26,6 +31,23 @@ public static boolean checkStorageAccessPermissions(Context context) {
2631
}
2732
}
2833

34+
@android.annotation.TargetApi(Build.VERSION_CODES.TIRAMISU)
35+
public static boolean checkMediaAccessPermissions(Context context) {//, Activity activity) {
36+
String audioPermission = Manifest.permission.READ_MEDIA_AUDIO;
37+
String imagesPermission = Manifest.permission.READ_MEDIA_IMAGES;
38+
String videoPermission = Manifest.permission.READ_MEDIA_VIDEO;
39+
// Check for permissions and request them if needed
40+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
41+
// You have the permissions, you can proceed with your media file operations.
42+
// You don't have the permissions. Request them.
43+
// activity.requestPermissions(new String[]{audioPermission, imagesPermission, videoPermission}, REQUEST_MEDIA_PERMISSIONS);
44+
return context.checkSelfPermission(audioPermission) == PackageManager.PERMISSION_GRANTED &&
45+
context.checkSelfPermission(imagesPermission) == PackageManager.PERMISSION_GRANTED &&
46+
context.checkSelfPermission(videoPermission) == PackageManager.PERMISSION_GRANTED;
47+
}
48+
return false;
49+
}
50+
2951
public static ArrayList<FileListItem>
3052
prepareFileListEntries(ArrayList<FileListItem> internalList, File inter,
3153
ExtensionFilter filter, boolean show_hidden_files) {

library/src/main/java/com/developer/filepicker/view/FilePickerDialog.java

+111-35
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.graphics.Color;
88
import android.os.Build;
99
import android.os.Bundle;
10+
import android.util.Log;
1011
import android.view.View;
1112
import android.view.Window;
1213
import android.widget.AdapterView;
@@ -38,7 +39,10 @@
3839
@SuppressWarnings("unused")
3940
public class FilePickerDialog extends Dialog implements AdapterView.OnItemClickListener {
4041

42+
private static final String TAG = FilePickerDialog.class.getSimpleName();
43+
4144
private final Context context;
45+
private Activity activity;
4246
private ListView listView;
4347
private TextView dname, dir_path, title;
4448
private DialogProperties properties;
@@ -53,6 +57,7 @@ public class FilePickerDialog extends Dialog implements AdapterView.OnItemClickL
5357

5458
public static final int EXTERNAL_READ_PERMISSION_GRANT = 112;
5559

60+
@Deprecated
5661
public FilePickerDialog(Context context) {
5762
super(context);
5863
this.context = context;
@@ -61,6 +66,16 @@ public FilePickerDialog(Context context) {
6166
internalList = new ArrayList<>();
6267
}
6368

69+
public FilePickerDialog(Activity activity, Context context) {
70+
super(context);
71+
this.activity = activity;
72+
this.context = context;
73+
properties = new DialogProperties();
74+
filter = new ExtensionFilter(properties);
75+
internalList = new ArrayList<>();
76+
}
77+
78+
@Deprecated
6479
public FilePickerDialog(Context context, DialogProperties properties, int themeResId) {
6580
super(context, themeResId);
6681
this.context = context;
@@ -69,6 +84,16 @@ public FilePickerDialog(Context context, DialogProperties properties, int themeR
6984
internalList = new ArrayList<>();
7085
}
7186

87+
public FilePickerDialog(Activity activity, Context context, DialogProperties properties, int themeResId) {
88+
super(context, themeResId);
89+
this.activity = activity;
90+
this.context = context;
91+
this.properties = properties;
92+
filter = new ExtensionFilter(properties);
93+
internalList = new ArrayList<>();
94+
}
95+
96+
@Deprecated
7297
public FilePickerDialog(Context context, DialogProperties properties) {
7398
super(context);
7499
this.context = context;
@@ -77,6 +102,15 @@ public FilePickerDialog(Context context, DialogProperties properties) {
77102
internalList = new ArrayList<>();
78103
}
79104

105+
public FilePickerDialog(Activity activity, Context context, DialogProperties properties) {
106+
super(context);
107+
this.activity = activity;
108+
this.context = context;
109+
this.properties = properties;
110+
filter = new ExtensionFilter(properties);
111+
internalList = new ArrayList<>();
112+
}
113+
80114
@Override
81115
protected void onCreate(Bundle savedInstanceState) {
82116
super.onCreate(savedInstanceState);
@@ -197,33 +231,50 @@ protected void onStart() {
197231
positiveBtnNameStr
198232
);
199233
select.setText(positiveBtnNameStr);
200-
if (Utility.checkStorageAccessPermissions(context)) {
201-
File currLoc;
202-
internalList.clear();
203-
if (properties.offset.isDirectory() && validateOffsetPath()) {
204-
currLoc = new File(properties.offset.getAbsolutePath());
205-
FileListItem parent = new FileListItem();
206-
parent.setFilename(context.getString(R.string.label_parent_dir));
207-
parent.setDirectory(true);
208-
parent.setLocation(Objects.requireNonNull(currLoc.getParentFile())
209-
.getAbsolutePath());
210-
parent.setTime(currLoc.lastModified());
211-
internalList.add(parent);
212-
} else if (properties.root.exists() && properties.root.isDirectory()) {
213-
currLoc = new File(properties.root.getAbsolutePath());
234+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
235+
if (Utility.checkMediaAccessPermissions(context)) {
236+
//Permission granted...
237+
dir();
214238
} else {
215-
currLoc = new File(properties.error_dir.getAbsolutePath());
239+
//Permissions are not granted...
240+
Log.d(TAG, "Permissions are not granted");
241+
}
242+
} else {
243+
if (Utility.checkStorageAccessPermissions(context)) {
244+
Log.d(TAG, "Permission granted");
245+
dir();
246+
} else {
247+
Log.d(TAG, "Permission not granted");
216248
}
217-
dname.setText(currLoc.getName());
218-
dir_path.setText(currLoc.getAbsolutePath());
219-
setTitle();
220-
internalList = Utility.prepareFileListEntries(internalList, currLoc, filter,
221-
properties.show_hidden_files);
222-
mFileListAdapter.notifyDataSetChanged();
223-
listView.setOnItemClickListener(this);
224249
}
225250
}
226251

252+
private void dir() {
253+
File currLoc;
254+
internalList.clear();
255+
if (properties.offset.isDirectory() && validateOffsetPath()) {
256+
currLoc = new File(properties.offset.getAbsolutePath());
257+
FileListItem parent = new FileListItem();
258+
parent.setFilename(context.getString(R.string.label_parent_dir));
259+
parent.setDirectory(true);
260+
parent.setLocation(Objects.requireNonNull(currLoc.getParentFile())
261+
.getAbsolutePath());
262+
parent.setTime(currLoc.lastModified());
263+
internalList.add(parent);
264+
} else if (properties.root.exists() && properties.root.isDirectory()) {
265+
currLoc = new File(properties.root.getAbsolutePath());
266+
} else {
267+
currLoc = new File(properties.error_dir.getAbsolutePath());
268+
}
269+
dname.setText(currLoc.getName());
270+
dir_path.setText(currLoc.getAbsolutePath());
271+
setTitle();
272+
internalList = Utility.prepareFileListEntries(internalList, currLoc, filter,
273+
properties.show_hidden_files);
274+
mFileListAdapter.notifyDataSetChanged();
275+
listView.setOnItemClickListener(this);
276+
}
277+
227278
private boolean validateOffsetPath() {
228279
String offset_path = properties.offset.getAbsolutePath();
229280
String root_path = properties.root.getAbsolutePath();
@@ -393,24 +444,49 @@ public void markFiles(List<String> paths) {
393444

394445
@Override
395446
public void show() {
396-
if (!Utility.checkStorageAccessPermissions(context)) {
397-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
398-
((Activity) context).requestPermissions(new String[]{Manifest.permission
399-
.READ_EXTERNAL_STORAGE}, EXTERNAL_READ_PERMISSION_GRANT);
447+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
448+
if (Utility.checkMediaAccessPermissions(context)) {
449+
//Permission granted...
450+
super.show();
451+
positiveBtnNameStr = positiveBtnNameStr == null ?
452+
context.getResources().getString(R.string.choose_button_label) : positiveBtnNameStr;
453+
select.setText(positiveBtnNameStr);
454+
int size = MarkedItemList.getFileCount();
455+
if (size == 0) {
456+
select.setText(positiveBtnNameStr);
457+
} else {
458+
String button_label = positiveBtnNameStr + " (" + size + ") ";
459+
select.setText(button_label);
460+
}
461+
} else {
462+
//Permissions are not granted...
463+
Log.d(TAG, "Permissions are not granted");
400464
}
401465
} else {
402-
super.show();
403-
positiveBtnNameStr = positiveBtnNameStr == null ?
404-
context.getResources().getString(R.string.choose_button_label) : positiveBtnNameStr;
405-
select.setText(positiveBtnNameStr);
406-
int size = MarkedItemList.getFileCount();
407-
if (size == 0) {
408-
select.setText(positiveBtnNameStr);
466+
if (!Utility.checkStorageAccessPermissions(context)) {
467+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
468+
((Activity) context).requestPermissions(new String[]{Manifest.permission
469+
.READ_EXTERNAL_STORAGE}, EXTERNAL_READ_PERMISSION_GRANT);
470+
}
409471
} else {
410-
String button_label = positiveBtnNameStr + " (" + size + ") ";
411-
select.setText(button_label);
472+
super.show();
473+
positiveBtnNameStr = positiveBtnNameStr == null ?
474+
context.getResources().getString(R.string.choose_button_label) : positiveBtnNameStr;
475+
select.setText(positiveBtnNameStr);
476+
int size = MarkedItemList.getFileCount();
477+
if (size == 0) {
478+
select.setText(positiveBtnNameStr);
479+
} else {
480+
String button_label = positiveBtnNameStr + " (" + size + ") ";
481+
select.setText(button_label);
482+
}
412483
}
413484
}
485+
if (!Utility.checkStorageAccessPermissions(context)) {
486+
487+
} else {
488+
489+
}
414490
}
415491

416492
@Override

sample/build.gradle

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
apply plugin: 'com.android.application'
22

33
android {
4-
compileSdkVersion 31
4+
compileSdk 34
55

66
defaultConfig {
77
applicationId "com.developer.filepicker.file"
88
minSdkVersion 19
9-
targetSdkVersion 31
10-
versionCode 7
11-
versionName "8.0.20"
9+
targetSdkVersion 34
10+
versionCode 8
11+
versionName "9.0.0"
1212
}
1313
buildTypes {
1414
release {
1515
minifyEnabled false
1616
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
1717
}
1818
}
19+
namespace 'com.developer.filepicker.file'
1920
}
2021

2122
dependencies {
@@ -25,6 +26,6 @@ dependencies {
2526
implementation project(':library')
2627

2728
//AndroidX Libraries
28-
implementation 'androidx.appcompat:appcompat:1.4.1'
29-
implementation 'androidx.recyclerview:recyclerview:1.2.1'
29+
implementation 'androidx.appcompat:appcompat:1.6.1'
30+
implementation 'androidx.recyclerview:recyclerview:1.3.1'
3031
}

0 commit comments

Comments
 (0)