How to convert a content Uri into a File - android

I know there are a ton of questions about this exact topic, but after spending two days reading and trying them, none seamed to fix my problem.
This is my code:
I launch the ACTION_GET_CONTENT in my onCreate()
Intent selectIntent = new Intent(Intent.ACTION_GET_CONTENT);
selectIntent.setType("audio/*");
startActivityForResult(selectIntent, AUDIO_REQUEST_CODE);
retrieve the Uri in onActivityResult()
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AUDIO_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
if ((data != null) && (data.getData() != null)) {
audio = data.getData();
}
}
}
pass the Uri to another activity and retrieve it
Intent debugIntent = new Intent(this, Debug.class);
Bundle bundle = new Bundle();
bundle.putString("audio", audio.toString());
debugIntent.putExtras(bundle);
startActivity(debugIntent);
Intent intent = this.getIntent();
Bundle bundle = intent.getExtras();
audio = Uri.parse((String) bundle.get("audio"));
The I have implemented this method based on another SO answer. To get the actual Path of the Uri
public static String getRealPathFromUri(Activity activity, Uri contentUri) {
String[] proj = { MediaStore.Audio.Media.DATA };
Cursor cursor = activity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
and in the Debug activity's onCreate() I try to generate the file:
File audioFile = new File(getRealPathFromUri(this, audio));
This is how the error looks like:
Caused by: java.lang.NullPointerException
at java.io.File.(File.java:262)
at com.dancam.lietome.Debug.onCreate(Debug.java:35)
When I run the app I get a NPE on this last line. The audio Uri, isn't NULL though so I don't understand from what it is caused.
I'd really appreciate if you helped me out.
This is the library I'm trying to work with.
Note: I know exactly what NPE is, but even debugging I couldn't figure out from what it is caused in this specific case.

pass the Uri to another activity and retrieve it
Your other activity does not necessarily have rights to work with the content identified by the Uri. Add FLAG_GRANT_READ_URI_PERMISSION to the Intent used to start that activity, and pass the Uri via the "data" facet of the Intent (setData()), not an extra.
To get the actual Path of the Uri
First, there is no requirement that the Uri that you get back be from the MediaStore.
Second, managedQuery() has been deprecated for six years.
Third, there is no requirement that the path that MediaStore has be one that you can use. For example, the audio file might be on removable storage, and while MediaStore can access it, you cannot.
How to convert a content Uri into a File
On a background thread:
Get a ContentResolver by calling getContentResolver() on a Context
Call openInputStream() on the ContentResolver, passing in the Uri that you obtained from ACTION_GET_CONTENT, to get an InputStream on the content identified by the Uri
Create a FileOutputStream on some File, where you want the content to be stored
Use Java I/O to copy the content from the InputStream to the FileOutputStream, closing both streams when you are done

I ran into same problem for Android Q, so I end up creating a new file and use input stream from content to fill that file
Here's How I do it in kotlin:
private var pdfFile: File? = null
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
when (requestCode) {
REQUEST_CODE_DOC -> {
data.data?.let {
if (it.scheme.equals("content")) {
val pdfBytes =
(contentResolver?.openInputStream(it))?.readBytes()
pdfFile = File(
getExternalFilesDir(null),
"Lesson ${Calendar.getInstance().time}t.pdf"
)
if (pdfFile!!.exists())
pdfFile!!.delete()
try {
val fos = FileOutputStream(pdfFile!!.path)
fos.write(pdfBytes)
fos.close()
} catch (e: Exception) {
Timber.e("PDF File", "Exception in pdf callback", e)
}
} else {
pdfFile = it.toFile()
}
}
}
}
}
}
}

Daniele, you can get path of file directly from data like below in onActivityResult():
String gilePath = data.getData().getPath();

Related

Read .txt file from anywhere on the phone

In my app I have this code allowing the user to select a file :
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/plain");
startActivityForResult(intent,1);
The user can select the .txt file from anywhere in his phone, even from google drive. When the file selection is done I retrieve a Uri object corresponding to the file. The problem is I can't use this Uri to read the file because it is not valid. Here is my code :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
File file = new File(uri.toString());
try{
InputStream inputStream = new FileInputStream(file);
int content;
while ((content = inputStream.read()) != -1) {
Log.d("===>", String.valueOf((char) content));
}
}catch (Exception e){
Log.d("===>", e.toString());
}
}
}
}
I always get a fileNotFoundException. My question is, is there a way to read the selected file (without knowing in advance the location it will come from). And if not, is there a way to copy the selected file in a folder from which I would easily get it ?
The problem is I can't use this Uri to read the file because it is not valid.
That is because a Uri is not a file.
is there a way to read the selected file (without knowing in advance the location it will come from)
The user did not select a file. The user selected a piece of content.
To consume the content represented by the Uri, call openInputStream() on a ContentResolver, passing in the Uri. This gives you an InputStream that you can use to read in the content.

Cannot use Poly Picker multiple image picker library in Android

I am developing an Android app. In my app, I want to let user to choose multiple when user clicks upload button. So I used this library. I can successfully pop up dialog and choose multiple files. But the problem is when I convert URI of selected images to bitmap in onActivityResult, it is giving me error.
This is how I pop up picker in activity:
private void getImages() {
Intent intent = new Intent(GalleryActivity.this, ImagePickerActivity.class);
nl.changer.polypicker.Config pickerConfig = new nl.changer.polypicker.Config(R.color.white,R.color.blue,10,R.color.green);
ImagePickerActivity.setConfig(pickerConfig);
startActivityForResult(intent, INTENT_REQUEST_GET_IMAGES);
}
This is how I am converting to bitmap on result:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == INTENT_REQUEST_GET_IMAGES) {
Parcelable[] parcelableUris = data.getParcelableArrayExtra(ImagePickerActivity.EXTRA_IMAGE_URIS);
if (parcelableUris == null) {
return;
}
// Java doesn't allow array casting, this is a little hack
Uri[] uris = new Uri[parcelableUris.length];
System.arraycopy(parcelableUris, 0, uris, 0, parcelableUris.length);
if (uris != null) {
bitmaps = new ArrayList<Bitmap>();
for (Uri uri : uris) {
try{
if(uri!=null)
{
Bitmap bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
bitmaps.add(bmp);
}
}
catch (IOException e)
{
Toast.makeText(getBaseContext(),e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
if(bitmaps.size()>0)
{
confirmFileUpload();
}
}
}
}
}
As you can see above my code, it will reach to io exception block of try-catch statement.
This is the example of error toasted:
That kind of error throw whatever image I select. What is wrong with my code and how can I fix it?
Finally I found the solution. I problem was when I parse uri to string, the format is something like this:
/sdcard/download/filename.png
The uri string must be in this format:
file:///sdcard/download/filename.png
No Content Provider Found exception throws because my uri string does not have required prefix. So I convert the uri to string. Then added the prefix. Then I parse that string to URI back. Then it worked successfully.

Load file from external storage using chooser

So, I'm trying to load a simple .txt file like this:
private void showFileChooser() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("text/plain");
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(
Intent.createChooser(intent, "Select a File to Upload"),
FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(this, "Please install a File Manager.",
Toast.LENGTH_SHORT).show();
}
}
And of course, catching the result like this:
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();
It works great on genymotion and on my device if I use a file explorer that I have installed (File explorer, see image abovew), now, If use the chooser directly like this:
It says it cannot find the specified file. (FileNotFoundException)
Now, I've realized that the URIs I get from these two file choosers are different
content://com.android.externalstorage.documents/document/primary%3ADownload%2Ffile.txt <- THIS DOESNT WORK (android built in explorer)
content://media/external/file/44751 <- THIS WORKS (custom explorer)
Does anyone have any idea why I'm getting different URIs for the SAME file.
EDIT:
I tried to use a content resolver to get the file path from the URI like this:
public class Utils {
public static String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Files.FileColumns.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(proj[0]);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
Still no luck :(
#CommonsWare's asnwer must be the right way of solving this, but I'm not sure how to implement his solution.
I've ended up doing what #Paul Burke recomends on this link:
Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT
EDIT
For my particular case, this is how my code ended up. I leave this here for future reference. (I'm using #CommonsWare's explanation) see his answer above.
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
BufferedReader br = null;
if (inputStream != null) {
br = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append("\n");
}
} else {
subscriber.onError(new InputException("There's something seriously wrong with this file"));
}
} catch (IOException e) {
e.printStackTrace();
subscriber.onError(e);
}
I tried to use a content resolver to get the file path from the URI like this
There is no file path. A Uri does not necessarily point to a file that you can access on your local filesystem, just as the URL to this Web page does not necessarily point to a file that you can access on your local filesystem. The Uri might:
represent a file held in internal storage of the other app
represent a BLOB column value in a database
represent a file held in "the cloud", to be downloaded when requested
etc.
Use a ContentResolver and methods like openInputStream() to read in the content represented by the Uri, just like you would use HttpUrlConnection to read in the content represented by the URL for this Web page. openInputStream() takes the Uri as a parameter and returns an InputStream. You would use that InputStream the same way you would any other InputStream (e.g., FileInputStream, InputStream from HttpUrlConnection). The exact mechanics of that will depend a lot on the underlying data (e.g., read in a string, pass to BitmapFactory to decode a Bitmap).

How to open file save dialog in android?

I have a web service which give me a byte[] array according to image id . I want to convert these byte[] to file and store a file on android where user want like save file dialog box with file same format exactly it has.
Since this is the top result in google when you search for that topic and it confused me a lot when I researched it, I thought I add an update to this question.
Since Android 19 there IS a built in save dialog. You dont event need any permission to do it (not even WRITE_EXTERNAL_STORAGE).
The way it works is pretty simple:
//send an ACTION_CREATE_DOCUMENT intent to the system. It will open a dialog where the user can choose a location and a filename
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("YOUR FILETYPE"); //not needed, but maybe usefull
intent.putExtra(Intent.EXTRA_TITLE, "YOUR FILENAME"); //not needed, but maybe usefull
startActivityForResult(intent, SOME_INTEGER);
...
//after the user has selected a location you get an uri where you can write your data to:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == SOME_INTEGER && resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
//just as an example, I am writing a String to the Uri I received from the user:
try {
OutputStream output = getContext().getContentResolver().openOutputStream(uri);
output.write(SOME_CONTENT.getBytes());
output.flush();
output.close();
}
catch(IOException e) {
Toast.makeText(context, "Error", Toast.LENGTH_SHORT).show();
}
}
}
More here:
https://developer.android.com/guide/topics/providers/document-provider
The Android SDK does not provide its own file dialog, therefore you have to build your own.
You cant create a save file dialog but you can save files from ur application to android sd card with the help of below links
http://android-er.blogspot.com/2010/07/save-file-to-sd-card.html
http://www.blackmoonit.com/android/filebrowser/intents#intent.pick_file.new
First, you should create a dialog intent for saving the file, After selection by the user, you can write on that directory and specified the file without any read/write permissions. ( Since Android 19 )
Source:https://developer.android.com/training/data-storage/shared/documents-files#create-file
// Request code for creating a PDF document.
private final int SAVE_DOCUMENT_REQUEST_CODE = 0x445;
private File targetFile;
private void createFile() {
Uri reportFileUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", targetFile);
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_TITLE, targetFile.getName());
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when your app creates the document.
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
startActivityForResult(intent, SAVE_DOCUMENT_REQUEST_CODE );
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SAVE_DOCUMENT_REQUEST_CODE && resultCode == RESULT_OK){
Uri uri = data.getData();
saveFile(uri);
}
}
private void saveFile(Uri uri) {
try {
OutputStream output = getContentResolver().openOutputStream(uri);
FileInputStream fileInputStream = new FileInputStream(targetFile);
byte[] bytes = new byte[(int) targetFile.length()];
fileInputStream.read(bytes, 0, bytes.length);
output.write(bytes);
output.flush();
output.close();
Log.i(TAG, "done");
} catch (IOException e) {
Log.e(TAG, "onActivityResult: ", e);
}
}
#JodliDev already provided the accepted answer, however, startActivityForResult is now deprecated, so I want to provide my solution here using registerForActivityResult(ActivityResultContracts.CreateDocument())
First register a ActivityResultLauncher where you define what should happen with the result. We'll get the uri back that we can use for our OutpuStream. But make sure to initialize it at the beginning, otherwise you will get:
Fragments must call registerForActivityResult() before they are created (i.e. initialization, onAttach(), or onCreate()).
private var ics: String? = null
private val getFileUriForSavingICS = registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
if(ics.isNullOrEmpty())
return#registerForActivityResult
try {
val output: OutputStream? =
context?.contentResolver?.openOutputStream(uri)
output?.write(ics?.toByteArray())
output?.flush()
output?.close()
} catch (e: IOException) {
Toast.makeText(context, "Error", Toast.LENGTH_SHORT).show()
}
}
Then just call your ActivityResultLauncher with .launch(...) wherever it is needed.
getFileUriForSavingICS.launch("filename.txt")
And that's about it ;-)
You can also have a closer look at ActivityResultContracts.CreateDocument(). This method provides the document saving dialog, but there are other helpful functions inside (like for starting a camera intent). Check out:
https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts
for the possible ActivityResultContracts
Or https://developer.android.com/training/basics/intents/result for some more training material and also some information how a custom contract could be created!

Get Audio Recorded by RecorderAudio Activity

I've searched a lot, but didnt found the solution to capture the audio recorded by Recorder Activity.
private void onClick() {
Intent intent = new Intent();
intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
try {
startActivityForResult(intent, IDF_ACTIVITY_AUDIO);
} catch (ActivityNotFoundException e) {
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == IDF_ACTIVITY_AUDIO) {
final String folder = Environment.getExternalStorageDirectory() + "/myAudio/";
String pathAudio = data.getData().getPath();
Uri audioUri = data.getData();
// pathAudio == /external/audio/media/8
// audioUri /external/audio/media/8
File audio = new File(folder + "audioTest");
//how to getAudio from data and save in audio file???
}
}
}
This two methods show my problem. With the Uri object returned by Native Recorder Activity, I need to save the audio in my own file.
Anyone know how to do this??
Can you indicate some links to fully understand how Uri works?
EDIT:
The String '/external/audio/media/8' do not represent valid path. What this string means?
Look at Start audio recording with intent of MediaStore.Audio.Media.RECORD_SOUND_ACTION and Using Intent to record audio,
These both tutorial give you a URI after recording audio now using that uRI you can get absolute path of that file and you can also write that file where you want using simple File I/O operation.
EDIT:
new File(new URI(androidURI.toString()));
Hi i am also searching for storing the recorded files in my own folder
But you can get the exact file name using
String absolutepath=getRealPathFromURI(audioUri);
public String getRealPathFromURI(Uri contentUri)
{
String[] proj = { MediaStore.Audio.Media.DATA};
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = `enter code here`cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
System.out.println("absolutepath audiopath in getRealPathFromURI : "+cursor.getString(column_index));
return cursor.getString(column_index);
}

Categories

Resources