I am using the following code to allow the user to share a bitmap,
try {
File save_dir = Environment.getExternalStorageDirectory();
FileOutputStream out = new FileOutputStream(save_dir
+ "/test.jpg");
final_bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/jpeg");
share.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file:///" + save_dir + "/test.jpg"));
startActivity(Intent.createChooser(share,
getString(R.string.share_dialog_title)));
} catch (Exception e) {
Toast.makeText(mainActivity, "Error in sharing.",
Toast.LENGTH_LONG).show();
}
the problem is, the if the device has no SD Card, the file will not be saved.
is there is any good way to save it to the internal storage, in somewhere other apps can access, since saving it in the applications data directory will not allow other applications to access it.
Regards
Related
I am using an Intent to capture videos in my app. My code is similar to this (adapted from https://developer.android.com/training/camera-deprecated/photobasics):
File mVideo;
private File createVideoFile() throws IOException {
#SuppressLint("SimpleDateFormat")
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmssSSS").format(new Date());
String videoFileName = "VID_" + timeStamp + ".mp4";
File storageDir = Environment.getExternalStorageDirectory();
File movies = new File(storageDir, "Movies");
if (!movies.exists() && !movies.mkdir()) { // suprisingly even this works?!
Log.e(TAG, "could not create Movies directory");
throw new IOException();
}
mCurrentVideo = new File(movies, videoFileName);
}
private final ActivityResultLauncher<Uri> requestRecordVideoLauncher =
registerForActivityResult(new ActivityResultContracts.CaptureVideo(), success -> {
if (success) {
Log.i(TAG, "successfully recorded video")
assert(mVideo.canRead());
} else {
if (!mCurrentVideo.delete()) {
Log.w(TAG, "could not delete aborted video recording");
}
}
});
public void dispatchTakeVideoIntent() {
File videoFile;
try {
createVideoFile();
} catch (IOException ex) {
Log.i(TAG, "could not create file")
return;
}
Uri videoUri = FileProvider.getUriForFile(mContext, getPackageName() + ".provider", videoFile);
requestRecordVideoLauncher.launch(videoUri);
}
I have a file provider registered with this path:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
The major difference to the code in the developer manual is that I am using a path to public external storage. Thus, videos would usually be saved to the path /storage/emulated/0/Movies/VID_{DATE}{TIME}.
Testing on different devices and emulators with different API levels (21, 30, 33) concludes that this is a legal thing to do (it does not even need any permissions to read the generated files).
From what I have read in the developer references, with scoped storage an app can still access all media files it has previously created without requesting any permission (https://developer.android.com/training/data-storage/shared/media#storage-permission-not-always-needed). Additionally, the File API can still be used to access files in external storage (https://developer.android.com/about/versions/11/privacy/storage#media-direct-file-native).
Do you think, it is a good idea to trust that this will still work in later Android versions? Is there any other way to easily record a video to external storage?
In my app I am receiving intent to open the pdf file using "application/pdf" intent-filter in menifest.
After a lot of research I am trying following code to open the file.
try {
File f = new File("file://"+uri.getPath());
Toast.makeText(k.this, f.getAbsolutePath(), Toast.LENGTH_LONG).show();
Toast.makeText(k.this, f.exists()?"Y":"N", Toast.LENGTH_LONG).show();
parcelFileDescriptor = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
} catch (IOException e) {
e.printStackTrace();
}
When I click on a file from file manager and open it with my app, It says the file does not exist. That means I am not able to create file from URI.
So my question is how to get parcelFileDescriptor from URI.
Thanks to the comment of Mike M.
getContentResolver().openFileDescriptor()
opens the fileDescriptor correctly.
In my app I am adding a Share button through the ShareActionProvider class. I am trying to share a PNG which I pull from the file system. The problem is I get the following error thrown at me when I try to share it with the stock messaging app
com.google.android.mms.MmsException: /data/data/com.frostbytedev.wifiqr/files/QRCode.png: open failed: EACCES (Permission denied)
At first I thought it was my permissions but I have the following permissions in my Manifest.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
The place where I try to get it from the file system is here:
Uri uri = Uri.fromFile(new File(getFilesDir(), "/QRCode.png"));
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_STREAM,uri);
provider.setShareIntent(intent);
If you were wondering, he is the code where I save the image
String fileName = getFilesDir() + "/QRCode.png";
etSSID.setText(fileName);
OutputStream stream = null;
try {
stream = new FileOutputStream(fileName);
bmp.compress(Bitmap.CompressFormat.PNG, 80, stream);
stream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
How can I solve this issue?
if /data/data/com.frostbytedev.wifiqr is your app's private directory then yes, your app has permission to read that file. You don't even need the WRITE_EXTERNAL_STORAGE permission because it's "your" directory.
But once you share it with another app, that app needs permission to read the file as well. And that's per default not the case with files inside your app private directory. The error you get is from the MMS app having no access.
A simple way to fix the problem is to save the file to a place that can be read by every app. Essentially everything in Environment.getExternalStorageDirectory().
The next possibility is to make that file readable for other apps but keep it where you have it. File#setReadable(true, false) should do that.
Context also has nice methods to simplify creating files in readable mode.
String fileName = getFileStreamPath("QRCode.png").getPath();
etSSID.setText(fileName);
OutputStream stream = null;
try {
stream = openFileOutput("QRCode.png", Context.MODE_WORLD_READABLE);
bmp.compress(Bitmap.CompressFormat.PNG, 80, stream);
stream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
...
Uri uri = Uri.fromFile(getFileStreamPath("QRCode.png"));
.. share
I'm trying to share an image file which saved to internal storage using share intent.
after I intent image file doesn't display.
I used following code to save the image file
try {
FileOutputStream fos = openFileOutput("twitterimage.jpg", Context.MODE_PRIVATE);
// Writing the bitmap to the output stream
bikeBm.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (Exception e) {
Log.e("saveToInternalStorage()", e.getMessage());
}
//intent code
File internalFile = getFileStreamPath("twitterimage.jpg");
Uri uri = Uri.fromFile(internalFile);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM,new File(uri));
shareIntent.setType("image/jpeg");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(shareIntent, "send"));
when I check the file existance using above "uri", the image file exists
in the internal storage but checking the file using
String file = "data/data/com.bike.app/twitterimage.jpg";
File f = new File(file);
shows me the file not exist.
pls help me to solve this problem.
If i am gessing right you want to share images between to applications. Your probleme is that you used Context.MODE_PRIVATE when you write a file so other applications cannot have access to this file.
To share an image you can use MediaProvider to restrict access to you Media or simply used Context.MODE_WORLD_READABLE but the file will be public readable then.
hope that help
This is my first question here. I've searched for my doubt. I found similar questions but i haven't exactly got my answer. So please forgive me if i have done something wrong.
I'm trying to save an image from an ImageView in my app to a folder in my sdcard. Here's the code :-
public void save(View view) {
myImage.setDrawingCacheEnabled(true);
Bitmap imgV = myImage.getDrawingCache();
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/AVP_saved");
String fname="Image.png";
File file = new File(myDir, fname);
try {
FileOutputStream out = new FileOutputStream(file);
imgV.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
Toast.makeText(this, "Image Downloaded", 7000).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, e.getMessage(), 8000).show();
}
}
'save' method is the method assigned to a button. 'myImage' is the ImageView found by its id. I have already set the permissions in the manifest. The thing is, the image dosen't get saved and it says that the path dosen't exist. When I myself create the folder "AVP_saved", then the image gets saved. What do i have to edit in this code such that the app creates the folder by itself when i click the button?
Thanks for your time!
Add this code after File myDir = new File(root + "/AVP_saved");
if(!myDir.exists()) {
mydir.mkdir(); //you can else call mkdirs() if you have to create a complete directory hierarchy
}
It seems that in Java, it's not possible to create a directory hierarchy by creating just a file in it.
With this, you'll create your directory only if it doesn't exist (be careful, if the directory exists but it's a file, it will launch an exception maybe, so you can look for myDir.isDirectory() too).