I have a video that I save to .../Movies/MyApp/abcde.mp4. So I know where it is. When I load it through my app using an implicit intent to ACTION_GET_CONTENT, the path is returned as content:/media/external/video/media/82 when I do
data.getData().toString()
The problem with that path is that it works when I try to access it with MediaRecorder as
mVideoView.setVideoURI(Uri.parse(mVideoStringPath))
However if I try to convert it to a path in another thread (for a job queue), the file is not found
new File(mVideoStringPath)
when I use the technique (copy and paste) described at How to get file path in onActivityResult in Android 4.4, still get the error
java.lang.RuntimeException: Invalid image file
Also per my logging, the new technique shows the path to the video as
video path: /storage/emulated/0/Movies/MyApp/abc de.mp4
notice the space in abc de.mp4. that indeed is the name of the file. And the phone's camera app has no trouble playing
However if I try to convert it to a path in another thread (for a job queue), the file is not found
That is because it is not a path to a file. It is a Uri, which is an opaque handle to some data.
How to get actual path to video from onActivityResult
You don't. You use the Uri. There is no requirement that the Uri point to a file. There is no requirement that the Uri, if it happens to represent a file, represent one that you have direct filesystem access to.
you need to escape the space the the file path in order to construct a File object from it.
filepath.replace(" ", "\\ ");
Related
I am writing an android app in Android Q. I tried to modify an external image file acquired from the MediaStore in place.
The simplified logic is:
contentResolver.openInputStream(uri).use {
buffer = it.readBytes()
}
edit(buffer)
contentResolver.openOutputStream(uri, "wt").use {
it?.write(buffer)
}
Also, android:requestLegacyExternalStorage="true"> is set. The image can be modified in place successfully, but I realize there is also some problem:
MediaStore is not updated immediately after the file is updated. e.g. the size of the file is still the old size.
Sometime calling contentResolver.loadThumbnail right after modifying the file will result in
W/MediaStore: Failed to obtain thumbnail for content://media/external/images/media/31
java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
These problems lead me to think whether modifying the MediaStore file in place is an allowed action? If yes, what is the best practice to do this?
Let's say I package an image with my app and I want to open it with the default image viewer/whatever image viewer the user has chosen to be the default. How would I do that?
There's already this post: Open an image using URI in Android's default gallery image viewer but many of the answers are obsolete because due to the introduction of android N, a content provider must be used.
The only answer I can find is this one:
File file = ...;
final Intent intent = new Intent(Intent.ACTION_VIEW)//
.setDataAndType(VERSION.SDK_INT >= VERSION_CODES.N ?
android.support.v4.content.FileProvider.getUriForFile(this,getPackageName() + ".provider", file) : Uri.fromFile(file),
"image/*").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
but, according to the author of this solution, this code only works for images stored externally, not ones that may be packaged with my app.
You won't be able to open an image packaged with the app (in drawable or whatever resources) through an external application. You should first copy it into (at least) an internal file storage. After that you can implement a FileProvider to provide access to this file.
Let me know if you need more details on this. Hope it helped.
I have two parts to this question: 1) what is the best solution to my need, and 2) how do I do this?
1) I have a client app which sends bundles to a service app. the bundles can break the limit on bundle size, so I need to write the actual request out and read it in on the service side. Because of this, I can't write to my private internal storage. I've used these pages heavily, and haven't had luck: http://developer.android.com/guide/topics/data/data-storage.html
http://developer.android.com/training/basics/data-storage/files.html
My current understanding is that my best path is to use this to get a public dir:
File innerDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
I then add in my filename:
String fileName = String.valueOf(request.timestamp + "_avoidRoute"+count+++".ggr");
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
fos.write(routeString.getBytes());
fos.close();
When I try to write this to disk I get the error
java.lang.IllegalArgumentException: File /storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr contains a path separator
Of course it does - I need it to have a path. I've searched online for solutions to this error which tell me to us FileOutputStream to write a full path. I did, but while my app doesn't error and appears to create the file, I'm also not able to view it on my phone in Windows Explorer, leading me to believe that it is creating a file with private permissions. So this brings me to my post and two questions:
1) Is there a different approach I should be trying to take to share large amounts of data between my client and service apps?
2) If not, what am I missing?
Thanks all for reading and trying to help!
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
This is not an appropriate use of Context's openFileOutput() method as that does not take a full path, but rather a filename within an app's private storage area.
If you are going to develop a full path yourself, as you have, then use
fos = new FileOutputStream(fullPath)
The Sharing permission setting is not applicable to the External Storage, though you will need a manifest permission to write (and implicitly read) on your creator, and the one for reading on your consumer.
Or, instead of constructing a full path, you could use your private storage with a filename and Context.MODE_WORLD_WRITEABLE (despite the being deprecated as an advisory) and pass the absolute path of the result to the other app to use with new FileInputStream(path).
Or you could use any of the other data interchange methods - content providers, local sockets, etc.
I am trying to read an image in my C++ code
LOGD("Loading image '%s' ...\n", (*inFile).c_str());;
Mat img = imread(*inFile, CV_LOAD_IMAGE_GRAYSCALE);
CV_Assert(img.data != 0);
and get the following output:
09-25 17:08:24.798: D/IRISREC(12120): Loading image '/data/data/com.example.irisrec/files/input/osoba1.jpg' ...
09-25 17:08:24.798: E/cv::error()(12120): OpenCV Error: Assertion failed (img.data != 0) in int wahet_main(int, char**), file jni/wahet.cpp, line 4208
The file exists. But strange is, that if I try to preview the image using Root File Browser it is just black. I copied the files there manually.
EDIT:
The code works fine under Windows with .png and .jpg format. I am just trying to port an existing C++ project for Iris Recognition to Android.
imread() determines the type of file based on its content not by the file extension. If the header of the file is corrupted, it makes sense that the method fails.
Here are a few things you could try:
Copy those images back to the computer and see if they can be opened by other apps. There's a chance that they are corrupted in the device;
Make sure there is a file at that location and that your user has permission to read it;
Test with types of images (jpg, png, tiff, bmp, ...);
For testing purposes it's always better to be more direct. Get rid of inFile:
Example:
Mat img = imread("/data/data/com.example.irisrec/files/input/osoba1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (!img.data) {
// Print error message and quit
}
When debugging, first try to get more data on the problem.
It's an unfortunate design that imread() doesn't provide any error info. The docs just say that it'll fail "because of missing file, improper permissions, unsupported or invalid format".
Use the debugger to step into the code if you can. Can you tell where it fails?
Search for known problems, stackoverflow.com/search?q=imread, e.g. imread not working in OpenCV.
Then generate as many hypotheses as you can. For each one, think of a way to test it. E.g.
The image file is malformed (as #karlphillip offered). -- See if other software can open the file.
The image file is not a supported format. -- Verify the file format on your desktop. Test that desktop OpenCV can read it. Check the docs to verify the image formats that AndroidCV can read.
The image file is not at the expected path. -- Write code to test if there's a file at that path, and verify its length.
The image file does not have read permission. -- Write code to open the file for reading.
A problem with the imread() arguments. -- Try defaulting the second argument.
I was able to solve this issue only by copying the image files in code.I stored them in my asset folder first and copied them to internal storage following this example.
If someone can explain this to me please do this.
It could be a permission issue.You would have to request the permission from Java code in your Activity class like this in Android 6.0 or above. Also make sure that in your AndroidManifest.xml, you have the the following line :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
In your activity file add this:
if (PermissionUtils.requestPermission(
this,
HOME_SCREEN_ACTIVITY,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
Mat image = Imgcodecs.imread(filePath,Imgcodecs.IMREAD_COLOR);
}
I struggled a long time to find this and I was getting Mat object null for all the time before.
I have few html files in assets folder of my application. My application loads these files depending on the device language. When I check for the existance of the file it say does not exist, but when I load that file using browser.loadUrl(filename), it loads it fine.
Following code will help you to understand my problem:
String filename="file:///android_asset/actualfilemname.html";
File f = new File(filename);
if(!f.exist){
filename = "file:///android_asset/newfile.html";[Everytime it loads this file even though I have actualfilename.html in the folder]
}
browser.loadUrl(filename);
[it loads the newfile.html but not actualfilename.html]
You can't use File for resources. You'll need to use the AssetManager for that.
(In the off-chance that File does handle resources, which I don't think it does, you'll have to convert the path to a URI first, for example using URI.create(). File(String) expects a path, not a URI.)
Is this the exact code you are using? you probably want to be calling f.exists() not filename.exist().
Edit: try working with the AssetManager instead of hard coding your file path. My best guess is that the file path you are using is not exactly how it supposed to be.