Skip to content

Commit c46c289

Browse files
Added full support to Android11+
1 parent b4b5cf6 commit c46c289

8 files changed

Lines changed: 250 additions & 27 deletions

File tree

Readme.md

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Step 2. Add the dependency
5050
Step 1. Directly add the dependency in application build.gradle file:
5151

5252
dependencies {
53-
implementation 'io.github.tutorialsandroid:filepicker:9.1.4'
53+
implementation 'io.github.tutorialsandroid:filepicker:9.2.5'
5454
}
5555

5656
### Usage
@@ -82,8 +82,17 @@ Step 1. Directly add the dependency in application build.gradle file:
8282
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
8383
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
8484

85+
<!-- Now on android 11 and above if you want to access other file types like csv,doc,pdf etc...
86+
You have to ask user a special permission that is MANAGE_EXTERNAL_STORAGE. But use this permission
87+
at your own risk because if you are publishing app on google play-store then you can encounter some
88+
issues. Use this permission only when your app core functionality is to read/write/delete. See the
89+
below link for more reference on this permission-->
90+
<!-- https://support.google.com/googleplay/android-developer/answer/10467955 -->
91+
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
92+
8593
<!-- If you are targeting your app from android version 4.4 to the latest version of android then
86-
you have to call all the above permissions as mentioned -->
94+
you have to call all the above permissions as mentioned except MANAGE_EXTERNAL_STORAGE use it only
95+
when needed.-->
8796
```
8897

8998
## FilePickerDialog
@@ -151,6 +160,164 @@ Marshmallow and above requests for the permission on runtime. You should overrid
151160
}
152161
```
153162

163+
### Android11 and above Instructions to get all types file formats:
164+
165+
Step 1: In your AndroidManifest.xml file add this permissions:
166+
167+
```xml
168+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
169+
android:maxSdkVersion="32" />
170+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
171+
android:maxSdkVersion="32" />
172+
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
173+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
174+
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
175+
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
176+
```
177+
178+
Step 2: Then in your Activity file ask for media permissions:
179+
180+
```java
181+
public class MainActivity extends AppCompatActivity {
182+
//...Your activity code goes here like onCreate() methods and all...
183+
184+
private final static int APP_STORAGE_ACCESS_REQUEST_CODE = 501;
185+
private static final int REQUEST_STORAGE_PERMISSIONS = 123;
186+
private static final int REQUEST_MEDIA_PERMISSIONS = 456;
187+
private final String readPermission = android.Manifest.permission.READ_EXTERNAL_STORAGE;
188+
private final String writePermission = android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
189+
190+
private void checkPermissions() {
191+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
192+
//As the device is Android 13 and above so I want the permission of accessing Audio, Images, Videos
193+
//You can ask permission according to your requirements what you want to access.
194+
String audioPermission = android.Manifest.permission.READ_MEDIA_AUDIO;
195+
String imagesPermission = android.Manifest.permission.READ_MEDIA_IMAGES;
196+
String videoPermission = android.Manifest.permission.READ_MEDIA_VIDEO;
197+
// Check for permissions and request them if needed
198+
if (ContextCompat.checkSelfPermission(MainActivity.this, audioPermission) == PackageManager.PERMISSION_GRANTED &&
199+
ContextCompat.checkSelfPermission(MainActivity.this, imagesPermission) == PackageManager.PERMISSION_GRANTED &&
200+
ContextCompat.checkSelfPermission(MainActivity.this, videoPermission) == PackageManager.PERMISSION_GRANTED) {
201+
// You have the permissions, you can proceed with your media file operations.
202+
//Showing dialog when Show Dialog button is clicked.
203+
filePickerDialog.show();
204+
} else {
205+
// You don't have the permissions. Request them.
206+
ActivityCompat.requestPermissions(MainActivity.this, new String[]{audioPermission, imagesPermission, videoPermission}, REQUEST_MEDIA_PERMISSIONS);
207+
}
208+
} else {
209+
//Android version is below 13 so we are asking normal read and write storage permissions
210+
// Check for permissions and request them if needed
211+
if (ContextCompat.checkSelfPermission(MainActivity.this, readPermission) == PackageManager.PERMISSION_GRANTED &&
212+
ContextCompat.checkSelfPermission(MainActivity.this, writePermission) == PackageManager.PERMISSION_GRANTED) {
213+
// You have the permissions, you can proceed with your file operations.
214+
// Show the file picker dialog when needed
215+
filePickerDialog.show();
216+
} else {
217+
// You don't have the permissions. Request them.
218+
ActivityCompat.requestPermissions(MainActivity.this, new String[]{readPermission, writePermission}, REQUEST_STORAGE_PERMISSIONS);
219+
}
220+
}
221+
}
222+
223+
@Override
224+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
225+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
226+
if (requestCode == REQUEST_STORAGE_PERMISSIONS) {
227+
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
228+
// Permissions were granted. You can proceed with your file operations.
229+
//Showing dialog when Show Dialog button is clicked.
230+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
231+
//Android version is 11 and above so to access all types of files we have to give
232+
//special permission so show user a dialog..
233+
accessAllFilesPermissionDialog();
234+
} else {
235+
//Android version is 10 and below so need of special permission...
236+
filePickerDialog.show();
237+
}
238+
} else {
239+
// Permissions were denied. Show a rationale dialog or inform the user about the importance of these permissions.
240+
showRationaleDialog();
241+
}
242+
}
243+
244+
//This conditions only works on Android 13 and above versions
245+
if (requestCode == REQUEST_MEDIA_PERMISSIONS) {
246+
if (grantResults.length > 0 && areAllPermissionsGranted(grantResults)) {
247+
// Permissions were granted. You can proceed with your media file operations.
248+
//Showing dialog when Show Dialog button is clicked.
249+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
250+
//Android version is 11 and above so to access all types of files we have to give
251+
//special permission so show user a dialog..
252+
accessAllFilesPermissionDialog();
253+
}
254+
} else {
255+
// Permissions were denied. Show a rationale dialog or inform the user about the importance of these permissions.
256+
showRationaleDialog();
257+
}
258+
}
259+
}
260+
261+
private boolean areAllPermissionsGranted(int[] grantResults) {
262+
for (int result : grantResults) {
263+
if (result != PackageManager.PERMISSION_GRANTED) {
264+
return false;
265+
}
266+
}
267+
return true;
268+
}
269+
270+
private void showRationaleDialog() {
271+
if (ActivityCompat.shouldShowRequestPermissionRationale(this, readPermission) ||
272+
ActivityCompat.shouldShowRequestPermissionRationale(this, writePermission) ) {
273+
// Show a rationale dialog explaining why the permissions are necessary.
274+
new AlertDialog.Builder(this)
275+
.setTitle("Permission Needed")
276+
.setMessage("This app needs storage permissions to read and write files.")
277+
.setPositiveButton("OK", (dialog, which) -> {
278+
// Request permissions when the user clicks OK.
279+
ActivityCompat.requestPermissions(MainActivity.this, new String[]{readPermission, writePermission}, REQUEST_STORAGE_PERMISSIONS);
280+
})
281+
.setNegativeButton("Cancel", (dialog, which) -> {
282+
dialog.dismiss();
283+
// Handle the case where the user cancels the permission request.
284+
})
285+
.show();
286+
} else {
287+
// Request permissions directly if no rationale is needed.
288+
ActivityCompat.requestPermissions(this, new String[]{readPermission, writePermission}, REQUEST_STORAGE_PERMISSIONS);
289+
}
290+
}
291+
292+
@RequiresApi(api = Build.VERSION_CODES.R)
293+
private void accessAllFilesPermissionDialog() {
294+
new AlertDialog.Builder(this)
295+
.setTitle("Permission Needed")
296+
.setMessage("This app needs all files access permissions to view files from your storage. Clicking on OK will redirect you to new window were you have to enable the option.")
297+
.setPositiveButton("OK", (dialog, which) -> {
298+
// Request permissions when the user clicks OK.
299+
Intent intent = new Intent(ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, Uri.parse("package:" + BuildConfig.APPLICATION_ID));
300+
startActivityForResult(intent, APP_STORAGE_ACCESS_REQUEST_CODE);
301+
})
302+
.setNegativeButton("Cancel", (dialog, which) -> {
303+
dialog.dismiss();
304+
// Handle the case where the user cancels the permission request.
305+
filePickerDialog.show();
306+
})
307+
.show();
308+
}
309+
310+
@Override
311+
public void onActivityResult(int requestCode, int resultCode, Intent data)
312+
{
313+
super.onActivityResult(requestCode, resultCode, data);
314+
if(requestCode == APP_STORAGE_ACCESS_REQUEST_CODE) {
315+
// Permission granted. Now resume your workflow.
316+
filePickerDialog.show();
317+
}
318+
}
319+
}
320+
```
154321
### Android13 and Above Instructions:
155322
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```:
156323
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
@@ -168,7 +335,7 @@ If you request both the ```READ_MEDIA_IMAGES``` permission and the ```READ_MEDIA
168335

169336
If your app was previously granted the ```READ_EXTERNAL_STORAGE``` permission, then any requested ```READ_MEDIA_*``` permissions are granted automatically when upgrading.
170337

171-
That's It. You are good to proceed further.
338+
That's It. You are good to proceed further. I hope this documentation will help you. You can contact me on telegram or instagram if having any issues id is given at start of readme.
172339

173340

174341
### Important:

library/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ group='com.github.TutorialsAndroid'
44

55
ext {
66
PUBLISH_GROUP_ID = 'io.github.tutorialsandroid'
7-
PUBLISH_VERSION = '9.1.4'
7+
PUBLISH_VERSION = '9.2.5'
88
PUBLISH_ARTIFACT_ID = 'filepicker'
99
PUBLISH_DESCRIPTION = 'Android Library to select files/directories from Device Storage'
1010
PUBLISH_URL = 'https://github.com/TutorialsAndroid/FilePicker'
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
<manifest
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"/>
1+
<manifest>
2+
<!-- FilePicker -->
103
</manifest>

library/src/main/java/com/developer/filepicker/controller/adapters/FileListAdapter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.content.Context;
44
import android.os.Build;
5+
import android.util.Log;
56
import android.view.LayoutInflater;
67
import android.view.View;
78
import android.view.ViewGroup;
@@ -29,6 +30,8 @@
2930
*/
3031
public class FileListAdapter extends BaseAdapter {
3132

33+
private static final String TAG = FileListAdapter.class.getSimpleName();
34+
3235
private ArrayList<FileListItem> listItem;
3336
private Context context;
3437
private DialogProperties properties;

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,16 @@ public class FilePickerDialog extends Dialog implements AdapterView.OnItemClickL
5050
private String titleStr = null;
5151
private String positiveBtnNameStr = null;
5252
private String negativeBtnNameStr = null;
53-
5453
public static final int EXTERNAL_READ_PERMISSION_GRANT = 112;
5554

55+
private String getFileExtension(String filePath) {
56+
int lastDotIndex = filePath.lastIndexOf('.');
57+
if (lastDotIndex != -1) {
58+
return filePath.substring(lastDotIndex + 1).toLowerCase();
59+
}
60+
return "";
61+
}
62+
5663
public FilePickerDialog(Context context) {
5764
super(context);
5865
this.context = context;
@@ -252,6 +259,7 @@ private void dir() {
252259
} else {
253260
currLoc = new File(properties.error_dir.getAbsolutePath());
254261
}
262+
255263
dname.setText(currLoc.getName());
256264
dir_path.setText(currLoc.getAbsolutePath());
257265
setTitle();
@@ -290,6 +298,9 @@ public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
290298
internalList = Utility.prepareFileListEntries(internalList, currLoc, filter,
291299
properties.show_hidden_files);
292300
mFileListAdapter.notifyDataSetChanged();
301+
302+
// Count the total number of files in the folder
303+
countFilesInFolder(currLoc);
293304
} else {
294305
Toast.makeText(context, R.string.error_dir_access,
295306
Toast.LENGTH_SHORT).show();
@@ -301,6 +312,21 @@ public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
301312
}
302313
}
303314

315+
public int countFilesInFolder(File folder) {
316+
int count = 0;
317+
if (folder != null && folder.isDirectory()) {
318+
File[] files = folder.listFiles();
319+
if (files != null) {
320+
for (File file : files) {
321+
if (file.isFile()) {
322+
count++;
323+
}
324+
}
325+
}
326+
}
327+
return count;
328+
}
329+
304330
public DialogProperties getProperties() {
305331
return properties;
306332
}
@@ -468,11 +494,6 @@ public void show() {
468494
}
469495
}
470496
}
471-
if (!Utility.checkStorageAccessPermissions(context)) {
472-
473-
} else {
474-
475-
}
476497
}
477498

478499
@Override

sample/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ android {
77
applicationId "com.developer.filepicker.file"
88
minSdkVersion 19
99
targetSdkVersion 34
10-
versionCode 12
11-
versionName "9.1.4"
10+
versionCode 13
11+
versionName "9.2.5"
1212
}
1313
buildTypes {
1414
release {

sample/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
1010
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
1111
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
12+
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
1213

1314
<application
1415
android:name="com.developer.filepicker.file.FilePickerApplication"

0 commit comments

Comments
 (0)