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.
Related
The app used to run. However, just recently it began to stop working. The device is running Android Nutella. Below is the LogCat.
java.lang.SecurityException: Permission Denial: reading com.google.android.music.store.ConfigContentProvider uri content://com.google.android.music.ConfigContent/one-key/2/ExplicitRestrictedByParentControl from pid=2500, uid=10373 requires the provider be exported, or grantUriPermission()
The app crashes in the the following code snippet on the last line(contained in a SongParser method).
String[] projection2 = {MediaStore.Audio.Media.ARTIST};
Uri songUri=null;
try {
songUri = Uri.parse("content://com.google.android.music.MusicContent/audio");
} catch (NullPointerException e){
e.printStackTrace();
}
if (songUri!=null) {
CursorLoader cl2 = new CursorLoader(context,
songUri, projection2, null, null, null);
cursor = cl2.loadInBackground();
I grant the Uri permissions in the following method after asking for permissions through the runtime permissions methods.
private void startService() {
//start intent to RssService for feedback
intent = new Intent(getActivity(), SongService.class);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContext().grantUriPermission("xxx.xxx.xxx.SongService",Uri.parse("content://com.google.android.music.MusicContent/audio"),Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(SongService.RECEIVER, resultReceiver);
getActivity().startService(intent);
}
Here is where SongService calls SongParser.
#Override
protected void onHandleIntent(Intent intent) {
List<String> eventItems= null;
if (haveNetworkConnection()) {
parser = new SongParser();
eventItems = parser.getAllArtists(getApplicationContext());
}
Bundle bundle = new Bundle();
bundle.putSerializable(ITEMS, (Serializable) eventItems);
ResultReceiver receiver = intent.getParcelableExtra(RECEIVER);
receiver.send(0, bundle);}}
I have contained the permissions in the manifest as well. Again, this exception seemingly happened on its own.
<permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
What's happening is that for some reason, the (exported) MusicContent provider will redirect to ConfigContentProvider, which is not exported.
It seems that the way to solve it is to open Google Play Music. If you haven't launched it in a while, it will redirect to com.google.android.music.store.ConfigContentProvider and trigger a SecurityException. It's kind of problematic but at least I can tell my users what to do. Let me know if you can come up with something better.
It might also be a good idea to file a bug.
You do not have access to that ContentProvider. It is not exported, and that app did not pass you a Uri that you can use to access it.
Since presumably the Uri is from an app that you did not write, apparently an update to that app changed this behavior.
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 am attempting to upload via ftp a file, named "advancedsettings.xml" located in path "/storage/emulated/0/advancedsettings.xml" from my Android device. It doesn't seem to be working; the file does not upload and the following exception is thrown:
01-06 17:56:17.498 28084-28084/com.name.example.appname E/SmsReceiverīš android.os.NetworkOnMainThreadException
I discovered that basically, an application cannot attempt to perform a networking operation "on its main thread".
I am new at Java but I understand, following from this, I must implement "ASync"; I haven't understood how to implement it. Could somebody help describe this to me and how I might implement it in respect of the below code?
My code is as follows:
public class FtpUpload {
// use this method to upload the file using file path global var and ftp code,
//then return the link string.
//TO DO: UID file name to prevent file already exists overwrite on server?
public void total() {
FTPClient con = null;
String dest_fname = "advancedsettings.xml"; // Added to create a destination file with a dynamically created name (same as the file name in /sdcard/ftp/)
try
{
con = new FTPClient();
con.connect("ftp.domain.co.uk");
// Check your USERNAME e.g myuser#mywebspace.com and check your PASSWORD to ensure they are OK.
if (con.login("username", "password"))
{
con.enterLocalPassiveMode(); // important!
con.setFileType(FTP.BINARY_FILE_TYPE);
String data = "/storage/emulated/0/advancedsettings.xml";
FileInputStream in = new FileInputStream(data);
boolean result = con.storeFile(dest_fname, in);
in.close();
if (result) Log.v("upload result", "succeeded");
con.logout();
con.disconnect();
} else { // This Error Log was created
// Create error log as a file
File log_file = new File("/storage/emulated/0/error.txt");
try {
FileWriter lfw = new FileWriter(log_file);
BufferedWriter lout = new BufferedWriter(lfw);
// Continue
lout.write("Upload Connection Failed!");
lout.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
Log.e("SmsReceiver", e1.toString());
}
}
}
catch (Exception e)
{
Log.e("SmsReceiver", e.toString());
}
}
Thank you in advance.
K
Shamefully I didn't initially come across this documentation on Async Tasks, which has proven invaluable.
With a bit of improv though, I got it working. I just modified my class as such:
private class FtpUpload extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
//code here
}
And used the following to call the above Async method:
new FtpUpload().execute();
Of course, you won't get very far with FTP networking without declaring the following user permissions in your manifest file (outside of the "application" tags):
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
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 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