Linking Error - No Write Permission - java

I have a problem with a project I am working on in Android Studio. The goal is to save a basic string into a .csv file then attach that file as an email attachment.
I cant write to the file, but I can share the file via FileProvider.getUriForFile.
I think the problem has something to do with these two linker error messages I get, the streamsavvy-1 is concerning bc my package name is com.team6.rifflegroup.streamsavvy
11-13 16:20:39.775 10286-10286/com.team6.rifflegroup.streamsavvy E/linker: readlink('') failed: No such file or directory [fd=31]
11-13 16:20:39.775 10286-10286/com.team6.rifflegroup.streamsavvy E/linker: warning: unable to get realpath for the library "/data/app/com.team6.rifflegroup.streamsavvy-1/oat/arm64/base.odex". Will use given name.
I build the file like this
File dataPath = new File(this.getFilesDir(), "xml");
File newData = new File(dataPath, FILE_NAME);
I have a paths.xml file within an xml directory under res that looks like this
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="my_files"
path="/"/>
</paths>
my write function looks like this
try {
FileWriter writer = new FileWriter(newData);
writer.append(csv);
writer.flush();
writer.close();
Toast.makeText(this, "SAVED", Toast.LENGTH_SHORT).show();
}catch (IOException e){
e.printStackTrace();
}
My Email intent looks like this
Uri contentUri = FileProvider.getUriForFile(this, "com.team6.rifflegroup.streamsavvy.FileProvider", newData);
this.grantUriPermission(getPackageName(), contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
emailIntent.setType("vnd.android.cursor.dir/email");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"myEmail#gmail.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, "File Attached");
emailIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
startActivity(Intent.createChooser(emailIntent, "Send email..."));
I give permission in my manifest here
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".dataLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.team6.rifflegroup.streamsavvy.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/paths"/>
</provider>
</application>
I feel like this is a problem with the way java builds its projects but I am not very familiar with the process. Any help or pointers would be greatly appreciated.
This is my first time posting here so I am so sorry if my post is out of context or improperly formatted.

Apologize for the long post. Figured it out.
had to declare the .mkdirs() call (not .mkdir()) after specifying the file.

Related

Error when sharing a CSV file saved in internal storage

I'm creating a contact tracing application using Java, the results of tracing are saved as detections.csv inside /storage/emulated/0/Android/media/com.idcta.proj.app/Sensor/ folder.
I'm trying to share this file on a button click, and my Manifest looks like this
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.idcta.proj.app">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
/>
<application
android:name="com.idcta.proj.app.AppDelegate"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:hardwareAccelerated="true"
android:requestLegacyExternalStorage="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
.....</appliction>
provider_paths.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
and inside my Contactlogs.java file inside the onCreate method
//request permissions for storage
requestPermissions();
//share button event
btn_share =(ImageButton)findViewById(R.id.btn_sharelogs);
btn_share.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),"detection.csv");
Uri path = FileProvider.getUriForFile(Contactlogs.this,BuildConfig.APPLICATION_ID+".provider",file);
Intent fileIntent = new Intent(Intent.ACTION_SEND);
fileIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
fileIntent.setType("text/*");
fileIntent.putExtra(Intent.EXTRA_STREAM, path);
Toast.makeText(Contactlogs.this," "+path,Toast.LENGTH_LONG).show();
startActivity(Intent.createChooser(fileIntent, "Send"));
}
});
But I keep getting the error:
E/ContentProviderNative: onTransact error from {P:29044;U:1000}
E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.idcta.proj.app.provider/external_files/detection.csv from pid=29044, uid=1000 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:873)
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:714)
at android.content.ContentProvider$Transport.query(ContentProvider.java:245)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:120)
at android.os.Binder.execTransactInternal(Binder.java:1165)
at android.os.Binder.execTransact(Binder.java:1134)
Any idea what I'm doing wrong here?
My Build.Gradle settings:
compileSdkVersion 30
buildToolsVersion "30.0.1"
defaultConfig {
applicationId 'com.idcta.proj.app'
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.2.0"
detections.csv inside /storage/emulated/0/Android/media/com.idcta.proj.app/Sensor/ folder.
That you got using getExternalMediaDirs()[0].
/storage/emulated/0/Android/media/com.idcta.proj.app/Sensor/detections.csv
So what did you code to have that path while saving?
Now when you want to serve the file you could use:
File file = new File(getExternalMediaDirs()[0], "Sensor/detections.csv");
Now you are hard coding your package name in the path.
Hardcoding should be avoided.

Permission Denial when trying to send CSV file to email, requires the provider be exported, or grantUriPermission()

I am generating a CSV file from data pulled from Firebase and then trying to attach it to an email (and about two weeks ago this code worked!), but I keep getting the same error of a toast message saving the file cannot be attached and the following error in my log cat when I perform this task now:
2020-08-20 17:05:43.355 11147-11268/com.example.cpd E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://com.example.cpd.provider/external/MyCPDAudit.csv from pid=30180, uid=1000 requires the provider be exported, or grantUriPermission()
My code to generate the email Intent is as follows
//INTENT TO SEND USER EMAIL
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
//SETS THE USERS EMAIL AS THE RECIPIENT EMAIL ADDRESS
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{user.getEmail()});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "My Audit Profile");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Thank you for using CPD Journal to build your CPD Audit Profile. Please see the attached file for your records.");
emailIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
File file = new File(csv);
Uri uri = FileProvider.getUriForFile(SavedAudit.this, "com.example.cpd.provider", file);
emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
//USER CAN SELECT HOW THEY WANT TO SHARE THE CSV FILE
startActivity(Intent.createChooser(emailIntent, "Pick an email provider"));
I have the following permissions in my Android Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
File provider in Manifest is
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.cpd.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
My file paths are
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
As per the logcat, I have tried exporting the provider in my Manifest file, but this crashes the app on launch.
I have tried adding the following two lines with my email Intent, but this results in the same log cat error:
String packageName = getApplicationContext().getPackageName();
grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
My csv and uri log as follows
2020-08-20 18:03:30.969 20914-20914/com.example.cpd D/TAG: csv = /storage/emulated/0/MyCPDAudit.csv
2020-08-20 18:03:30.974 20914-20914/com.example.cpd D/TAG: uri = content://com.example.cpd.provider/external/MyCPDAudit.csv
However, I'm not sure if I'm using this grantUriPermission method correctly by calling it like this - any ideas how to solve this?

Can't send file correct URI using FileProvider

I'm creating a file with this path
File file = new File(getExternalFilesDir(null) + "/package.apk");
then I'm trying to send it using this code
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(FileProvider.getUriForFile(UpdateActivity.this, getPackageName() + ".provider", file), "application/vnd.android.package-archive");
Log.d("uri",FileProvider.getUriForFile(UpdateActivity.this, getPackageName() + ".provider", file).toString());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
my android manifest is
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
and the provider_paths
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path name="files" path="." />
</paths>
After running code I'm getting There was a problem parsing the package error but if I open the file using file manager from path Android/my.package.name/files/package.apk it's parsing so the URI I'm sending is incorrect then I tried to print it and the result is
content://my.package.name.provider/files/package.apk
what am I doing wrong?
You forgot to add FLAG_GRANT_READ_URI_PERMISSION on the Intent. As it stands, the Uri is valid, but the installer has no rights to access its content.
Also note that the stock Android installer only supports content schemes as of Android 7.0. Older Android devices are limited to file.

Getting URI instead of File when using FileProvider

I am creating an app in which I let the user to share an audio file that is presen on the external storage.
I try to use this code but it is not working.
//This is getting the absolute path of the parent folder where the
//file is situated
File mFolder= new File(m_sdcard+m_confi);
// This take us to folder where the file is situated
File mAbFolder = new File(mFolder, "temp");
// Taking the files in an array
File[] mAllFiles= mAbFolder.listFiles();
//Getting the URI
Uri contentUri = FileProvider.getUriForFile(mContext, "com.androidpackagename.fileprovider", mImageFiles[1]);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setDataAndType(contentUri, mContext.getContentResolver().getType(contentUri));
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(intent);
Now when I am running this code, it shows me the share menu. But when I click on any item such as Gmail, it put the uri into the "TO" field.
And I also tried to share it on Whatsapp. When I select a user to share this, nothing happens and I get back to my app.
My manifest is :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidpackagename">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.androidpackagename.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepath" />
</provider>
</application>
</manifest>
My filepath xml is having
<external-path
name="external"
path="Android/data/com.androidpackagename/temp/" />
</paths>
Please help on this, thanks in advance.
I try to use this code but it is not working.
That is not how you use ACTION_SEND. Quoting the documentation:
Input: getType() is the MIME type of the data being sent. get*Extra can have either a EXTRA_TEXT or EXTRA_STREAM field, containing the data to be sent. If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the MIME type of the data in EXTRA_STREAM.
So, replace:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setDataAndType(contentUri, mContext.getContentResolver().getType(contentUri));
with:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(mContext.getContentResolver().getType(contentUri));
intent.putExtra(Intent.EXTRA_STREAM, contentUri);
(though it would be much more efficient for you to just put in the MIME type directly in setType(), rather than using getContentResolver().getType(contentUri), since hopefully you know what this file is and what its MIME type is)

Permission Denial With Broadcast Receiver

I am trying to create an app which enters a log message when I make an outgoing call.
However, when I run the code, I get a permission denial, despite the fact that I have entered in the permissions.
Denial Log:
"09-04 02:35:50.535 1294-1666/? W/BroadcastQueue﹕ Permission Denial: receiving Intent { act=android.intent.action.NEW_OUTGOING_CALL flg=0x10000010 (has extras) } to samples.varma.packagecom.testreceive2/.CallReceiver requires android.permission.PROCESS_OUTGOING_CALLS due to sender android (uid 1000)"
Manifest Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="samples.varma.packagecom.testreceive2" >
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:enabled="true"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
</application>
</manifest>
And here is the code for my receiver:
package samples.varma.packagecom.testreceive2;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;
public class CallReceiver extends BroadcastReceiver {
public CallReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state == null) {
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("TAG", "Outgoing Number: " + number);
} else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("TAG", "Incoming Number: " + number);
}
}
}
I am very new to this so there is a good chance that there are several errors or I am completely off base. Regardless I would greatly appreciate any guidance. Would anyone know why I am getting this denial?
Thanks
Edit:
It is also giving me these permission denials even though I have added the phone state permission.
The privileged phone-state permission is a system permission so I cannot add.
09-04 04:36:03.249 1294-1440/? W/BroadcastQueue﹕ Permission Denial: receiving Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } to samples.varma.packagecom.testreceive2/.CallReceiver requires android.permission.READ_PRIVILEGED_PHONE_STATE due to sender android (uid 1000)
09-04 04:36:03.271 1294-1308/? W/BroadcastQueue﹕ Permission Denial: receiving Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } to samples.varma.packagecom.testreceive2/.CallReceiver requires android.permission.READ_PHONE_STATE due to sender android (uid 1000)
1294-1308/? W/BroadcastQueue﹕ Permission Denial: receiving Intent { act=android.intent.action.PHONE_STATE flg=0x10 (has extras) } to samples.varma.packagecom.testreceive2/.CallReceiver requires android.permission.READ_PHONE_STATE due to sender android (uid 1000)
I have launched the same application on Android emulator and nothing helped, even
android:enabled="true"
android:exported="true"
The solution was to go to Settings->Apps -> MyApplication -> Permissions -> Toggle Phone Permission on.
Android Phone Permission for Application
I got it to work by following this link closely Intercepting outgoing call - what am I missing? (thanks ajit)
I ended up taking off the PHONE_STATE permission, adding android:enabled="true" and android:exported="true" to my receiver in the manifest, relocating the NEW_OUTGOING_CALL permission to below application(not sure if this is necessary), taking away the intended sdk versions and basically copying the receiver from the link.
Updated manifest code from receiver tag to manifest tag is:
<receiver
android:name=".testreceive3"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>-->
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />>-->
</manifest>
U need to apply the runtime permission int your code when your code running on Android 6.0 or above.
You should add the following thing in your Manifest receiver
<service android:name=".CallReceiver"
android:enabled="true"
android:exported="false" >
</service>
Use permission CALL_PHONE instead of OUTGOING
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Best solution is when you run the code activate usb debugging, make sure you select disable permissions monitor settings in developer settings ! App wont be asked for permissions by the OS anymore. Happy helping :)
This will work without changing anything in manifest!

Categories