Android File Chooser

Android file chooser

EDIT (02 Jan 2012):

I created a small open source Android Library Project that streamlines this process, while also providing a built-in file explorer (in case the user does not have one present). It's extremely simple to use, requiring only a few lines of code.

You can find it at GitHub: aFileChooser.


ORIGINAL

If you want the user to be able to choose any file in the system, you will need to include your own file manager, or advise the user to download one. I believe the best you can do is look for "openable" content in an Intent.createChooser() like this:

private static final int FILE_SELECT_CODE = 0;

private void showFileChooser() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);

try {
startActivityForResult(
Intent.createChooser(intent, "Select a File to Upload"),
FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
// Potentially direct the user to the Market with a Dialog
Toast.makeText(this, "Please install a File Manager.",
Toast.LENGTH_SHORT).show();
}
}

You would then listen for the selected file's Uri in onActivityResult() like so:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case FILE_SELECT_CODE:
if (resultCode == RESULT_OK) {
// Get the Uri of the selected file
Uri uri = data.getData();
Log.d(TAG, "File Uri: " + uri.toString());
// Get the path
String path = FileUtils.getPath(this, uri);
Log.d(TAG, "File Path: " + path);
// Get the file instance
// File file = new File(path);
// Initiate the upload
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}

The getPath() method in my FileUtils.java is:

public static String getPath(Context context, Uri uri) throws URISyntaxException {
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = { "_data" };
Cursor cursor = null;

try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow("_data");
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
// Eat it
}
}
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}

return null;
}

Implementing a File Picker in Android and copying the selected file to another location

STEP 1 - Use an Implicit Intent:

To choose a file from the device, you should use an implicit Intent

Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(chooseFile, "Choose a file");
startActivityForResult(chooseFile, PICKFILE_RESULT_CODE);

STEP 2 - Get the absolute file path:

To get the file path from a Uri, first, try using

Uri uri = data.getData();
String src = uri.getPath();

where data is the Intent returned in onActivityResult().

If that doesn't work, use the following method:

public String getPath(Uri uri) {

String path = null;
String[] projection = { MediaStore.Files.FileColumns.DATA };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);

if(cursor == null){
path = uri.getPath()
}
else{
cursor.moveToFirst();
int column_index = cursor.getColumnIndexOrThrow(projection[0]);
path = cursor.getString(column_index);
cursor.close();
}

return ((path == null || path.isEmpty()) ? (uri.getPath()) : path);
}

At least one of these two methods should get you the correct, full path.

STEP 3 - Copy the file:

What you want, I believe, is to copy a file from one location to another.

To do this, it is necessary to have the absolute file path of both the source and destination locations.

First, get the absolute file path using either my getPath() method or uri.getPath():

String src = getPath(uri);    /* Method defined above. */

or

Uri uri = data.getData();
String src = uri.getPath();

Then, create two File objects as follows:

File source = new File(src);
String filename = uri.getLastPathSegment();
File destination = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/CustomFolder/" + filename);

where CustomFolder is the directory on your external drive where you want to copy the file.

Then use the following method to copy a file from one place to another:

private void copy(File source, File destination) {

FileChannel in = new FileInputStream(source).getChannel();
FileChannel out = new FileOutputStream(destination).getChannel();

try {
in.transferTo(0, in.size(), out);
} catch(Exception){
// post to log
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
}

Try this. This should work.

Note: Vis-a-vis Lukas' answer - what he has done is use a method called openInputStream() that returns the content of a Uri, whether that Uri represents a file or a URL.

Another promising approach - the FileProvider:

There is one more way through which it is possible to get a file from another app. If an app shares its files through the FileProvider, then it is possible to get hold of a FileDescriptor object which holds specific information about this file.

To do this, use the following Intent:

Intent mRequestFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
mRequestFileIntent.setType("*/*");
startActivityForResult(mRequestFileIntent, 0);

and in your onActivityResult():

@Override
public void onActivityResult(int requestCode, int resultCode,
Intent returnIntent) {
// If the selection didn't work
if (resultCode != RESULT_OK) {
// Exit without doing anything else
return;
} else {
// Get the file's content URI from the incoming Intent
Uri returnUri = returnIntent.getData();
/*
* Try to open the file for "read" access using the
* returned URI. If the file isn't found, write to the
* error log and return.
*/
try {
/*
* Get the content resolver instance for this context, and use it
* to get a ParcelFileDescriptor for the file.
*/
mInputPFD = getContentResolver().openFileDescriptor(returnUri, "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("MainActivity", "File not found.");
return;
}
// Get a regular file descriptor for the file
FileDescriptor fd = mInputPFD.getFileDescriptor();
...
}
}

where mInputPFD is a ParcelFileDescriptor.

References:

1. Common Intents - File Storage.

2. FileChannel.

3. FileProvider.

4. Requesting a Shared File.

How to add Internal and External storage to File Chooser in android

The user can tap the "..." affordance in the action bar and choose "Show internal storage" to display those options.

There is no official support for anything on ACTION_GET_CONTENT or ACTION_OPEN_DOCUMENT to show internal storage options automatically, though hopefully this will be supported someday.

Android File Chooser not calling from Android Webview

It is not the gradle file error. You just need to provide custom WebChromeClient like below.

class MyWebChromeClient extends WebChromeClient {
// For 3.0+ Devices (Start)
// onActivityResult attached before constructor
protected void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}


// For Lollipop 5.0+ Devices
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}

uploadMessage = filePathCallback;

Intent intent = fileChooserParams.createIntent();
try {
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
uploadMessage = null;
Toast.makeText(WebLink.this, "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}

//For Android 4.1 only
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE);
}

protected void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
}

and it in your webview like below

webview.setWebChromeClient(new MyWebChromeClient());

some other useful stuff/variables to be declared globally.

public ValueCallback<Uri[]> uploadMessage;
private ValueCallback<Uri> mUploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;

make sure you have all the read/write permissions

UPDATE

Use below lines to provide access to files from storage.

webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setAllowContentAccess(true);
webview.getSettings().setAllowFileAccess(true);

// EDIT, add this line also
webview.getSettings().setJavaScriptEnabled(true);

UPDATE 2

Get the result in onActivityResult method. You can use the result given like below.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null)
return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
uploadMessage = null;
}
} else if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage)
return;
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
Uri result = intent == null || resultCode != WebLink.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else
Toast.makeText(WebLink.this, "Failed to Upload Image", Toast.LENGTH_LONG).show();
}

How to allow selection of CSV in a File Chooser Intent in Android

When using EXTRA_MIME_TYPES you need to call setType("*/*"). See the OpenFile section of Common Intents.

Also, you should consider using the Activity Results API instead of startActivityForResult() since it provides more type safety and the latter has been deprecated. The one you are looking for is ActivityResultContracts.GetContent

How to Select File on android using Intent

the type of a file is .txt

Then use text/plain as a MIME type. As Ian Lake noted in a comment, file/* is not a valid MIME type.

Beyond that, delete getRealPathFromURI() (which will not work). There is no path, beyond the Uri itself. You can read in the contents identified by this Uri by calling openInputStream() on a ContentResolver, and you can get a ContentResolver by calling getContentResolver() on your Activity.

Android Programming: Cannot read file from file picker Intent

// File picker implementation
private fun chooseFile(view:View) {
//only the below specified mime type is allowed in the picker
val mimeTypes = arrayOf(
"application/msword",
"application/vnd.ms-powerpoint",
"application/vnd.ms-excel",
"text/plain",
"application/pdf"
)
println("chooseFile activated!");
var selectFile = Intent(Intent.ACTION_GET_CONTENT)
selectFile.type = if (mimeTypes.size == 1) mimeTypes[0] else "*/*"
if (mimeTypes.isNotEmpty()) {
selectFile.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
}
selectFile = Intent.createChooser(selectFile, "Choose a file")
startActivityForResult(selectFile, READ_IN_FILE)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 200) { // Step 1: When a result has been received, check if it is the result for READ_IN_FILE
if (resultCode == Activity.RESULT_OK) { // Step 2: Check if the operation to retrieve thea ctivity's result is successful
// Attempt to retrieve the file
try {
data?.data?.let {
contentResolver.openInputStream(it)
}?.let {
val r = BufferedReader(InputStreamReader(it))
while (true) {
val line: String? = r.readLine() ?: break
println(line)
}
}

} catch (e: Exception) { // If the app failed to attempt to retrieve the error file, throw an error alert
Toast.makeText(
this,
"Sorry, but there was an error reading in the file",
Toast.LENGTH_SHORT
).show()
}
}
}
}


Related Topics



Leave a reply



Submit