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
Related
I have permissions for read and writing on AndroidManifest:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
... because I want to copy one file. I'm performing this process in two steps:
1. Launching an Intent so the user creates the file where he wants:
This code is mostly the example of the Android developers site.
private void createFile() {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/vnd.sqlite3");
intent.putExtra(Intent.EXTRA_TITLE, "test.db");
startActivityForResult(intent, CREATE_FILE);
}
2. Copy the file.
The intent returns a Uri, so inside the onActivityResult:
try {
destinationOutputStream = getContentResolver().openOutputStream(data.getData());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
(where data is the Intent), I'm able to get the output stream.
Finally, and according to the documentation, I should be able to copy the file:
try {
Long totalBytes = Files.copy(originalPath, destinationOutputStream);
} catch (IOException e) {
e.printStackTrace();
}
(where originalPath is the path (of type Path) where the original file is stored).
But, on runtime, I'm getting the following error:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
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.
Sorry for the title, I was not sure how to word it, my problem with my app is taking a photo and getting its Uri content to write to a new file using input/output stream. So far I have this
Intent take_photo_intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (take_photo_intent.resolveActivity(getActivity().getPackageManager()) != null)
{
try
{
// create file from a template
image_file = createFileForImage();
}
catch (IOException e)
{
e.printStackTrace();
}
// check if file is null
if(image_file != null)
{
// create uri using file and applying a provider
image_uri = FileProvider.getUriForFile(getContext(), PROVIDER, image_file);
take_photo_intent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri);
image_path = image_uri.getPath();
// start activity
startActivityForResult(take_photo_intent, TAKE_PHOTO);
}
}
in this case, the return bitmap is what I need to display the thumbnail quality image in my app
my issue comes with trying to get the full scaled image and save it to a custom folder in the android devices storage.
I been following this tutorial
https://developer.android.com/training/camera/photobasics.html#Save%20the%20Full-size%20Photo
I am not 100% sure I set up the provider correctly, the app compiles and runes, my issue is with the the Uri.
if you go back to this chunk of my app
image_uri = FileProvider.getUriForFile(getContext(), PROVIDER, image_file);
take_photo_intent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri);
image_path = image_uri.getPath();
the image_file is a File object I created in a folder in the external storage, that part is fine since i used that path for other things and can verify it in a file manager. this is not used until later.
The provider "seems to work" since the app runs
my issue is the image_uri. My thoughts is, i have a empty file saved in that dir i created, now I need to read the contents of image_uri into that file, so I did this in the onActivityResult
// this will hold the Uri data
InputStream in_file = null;
// this will be used to write the input stream to the file
OutputStream out_file = null;
// check if Uri is null
if(image_uri != null) {
try {
// get the Uri data into an input stream
in_file = getContext().getContentResolver().openInputStream(image_uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// check for nulls
if (in_file != null && image_file != null) {
// create output stream linked to new file location
try {
out_file = new FileOutputStream(image_file);
Log.i("IMAGE", "open outsream");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// create temp byte array
byte[] image_bytes = null;
try {
// use apache tools to write bytes to that file using the outputstream
image_bytes = IOUtils.toByteArray(in_file);
} catch (IOException e) {
e.printStackTrace();
}
if (image_bytes != null && out_file != null) {
try {
out_file.write(image_bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Now im thinking, ok, I have the picture just taken which the provider set up, I create an external file onto sd card which I know works, and I have an input stream to the uri and an outputstream to the file, and used IOUtils.toByteArray to write tho.
However, my problem is the uri data is all blank. by that i mean the bytes are all 0's or size of array after that IOUtils.toByteArray call is 0. so I am guessing it must be a problem with the provider. I am still not sure how it works, going off the tutorial, I have this
AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.myapp.main.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
res/xml/file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="my_images" path="Android/data/com.myapp/files/Pictures" />
As I said, I am not sure how this works, is /files/Pictures a folder in my apps internal storage by default? do I have to make it?
when logging out some stuff, this is what I got
image_uri = FileProvider.getUriForFile(getContext(), PROVIDER, image_file);
Log.i("IMAGE", "DEBUG--->: " + image_uri.getPath());
I/IMAGE: DEBUG--->: /my_images/camera_shots/20160808_190857-1642881770.jpg
and I never created that folder, so I am confused on how this all works.
I've been trying to encrypt files and write those files back on to the same place. But I got the error message saying "java.io.FileNotFoundException: /storage/emulated/0/New file.txt: open failed: EACCES (Permission denied)".
My Manifest file is this
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tdk.mytestapplication2">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
I think I have provided correct permission there. And the code I am using to encrypt files is this.
public static void encrypt(SecretKey secretKey, String filePath){
try {
// Here you read the cleartext.
FileInputStream fis = new FileInputStream(filePath);
// This stream write the encrypted text. This stream will be wrapped by another stream.
FileOutputStream fos = new FileOutputStream(filePath);
// Create cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
}catch(IOException e){
e.printStackTrace();
}catch (NoSuchAlgorithmException e){
e.printStackTrace();
}catch(NoSuchPaddingException e){
e.printStackTrace();
}catch(InvalidKeyException e){
e.printStackTrace();
}
}
And I used this method inside a button
Button btnEncrypt = (Button) findViewById(R.id.btnEnc);
btnEncrypt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
aesKey = EncAndDec.generateKey();
String filePath = editText.getText().toString();
//Generating the file hash
String md5Hash = MD5Hash.getMD5(filePath);
System.out.println(aesKey.toString());
System.out.println(filePath);
System.out.println(md5Hash);
//Encrypting the file
for(int i=1; i<100; i++) {
EncAndDec.encrypt(aesKey, filePath);
}
}
});
Still I couldn't configure this error. Please someone help!
If you are running in Android 29 then you have to use scoped storage or for now, you can bypass this issue by using:
android:requestLegacyExternalStorage="true"
in manifest in the application tag.
I suspect you are running Android 6.0 Marshmallow (API 23) or later. If this is the case, you must implement runtime permissions before you try to read/write external storage.
Implement runtime permission for running your app on Android 6.0 Marshmallow (API 23) or later.
or you can manually enable the storage permission-
goto settings>apps> "your_app_name" >click on it >then click permissions> then enable the storage. Thats it.
But i suggest go the for first one which is, Implement runtime permissions in your code.
On Android 11, apps can no longer access files in any other app's dedicated, app-specific directory within external storage.
To protect user privacy, on devices that run Android 11 or higher, the system further restricts your app's access to other apps' private directories.
Request MANAGE_EXTERNAL_STORAGE permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage"/>
Request External Storage Permissions
ActivityCompat.requestPermissions( this,
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.MANAGE_EXTERNAL_STORAGE
}, 1
);
Checking permission of MANAGE_EXTERNAL_STORAGE
// If you have access to the external storage, do whatever you need
if (Environment.isExternalStorageManager()){
// If you don't have access, launch a new activity to show the user the system's dialog
// to allow access to the external storage
}else{
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
For SDK 29 :
String str1 = "";
folder1 = new File(String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)));
if (folder1.exists()) {str1 = folder1.toString() + File.separator;}
public static void createTextFile(String sBody, String FileName, String Where) {
try {
File gpxfile = new File(Where, FileName);
FileWriter writer = new FileWriter(gpxfile);
writer.append(sBody);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Then you can save your file like this :
createTextFile("This is Content","file.txt",str1);
I'm developing a game in Android. The game has many levels and a Level Editor. So when a user make a level, the data are saving as Xml file. So I want to upload this Xml file to internet to share the other users. I searhed and tried these below codes. But It didn't work. The whole code like this:
String FTP_HOST= "185.27.134.11";
String FTP_USER = "fees0_14042425";
String FTP_PASS ="kadi1sd22";
File f = new File(Environment.getExternalStorageDirectory()+"/kadirGameLevels1/a.png");
FTPClient client = new FTPClient();
try {
client.connect(FTP_HOST,21);
client.login(FTP_USER, FTP_PASS);
client.setType(FTPClient.TYPE_BINARY);
client.changeDirectory("/levels/");
client.upload(f, new MyTransferListener());
} catch (Exception e) {
e.printStackTrace();
try {
client.disconnect(true);
} catch (Exception e2) {
e2.printStackTrace();
}
}
But even if I only use this single line, it still stop running. Did I something wrong with is integration or anything else?
FTPClient client = new FTPClient();
Make sure you have the INTERNET permission in your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
This makes sure your app has the right permission to access the internet.
Also don't put any networking code in the main UI thread or you will likely get a NetworkOnMainThreadException.
Instead put all your FTP-connecting/accessing code into an AsyncTask: https://stackoverflow.com/a/6343299/833647