Android 11 introduced multiple changes to file storage and access. Apparently one of them is that one can no longer target output to '/dev/null' (my scenario is actually exactly explained in this old question).
Although the cited question solved the particular issue, one thing remains unanswered: what is Android 11's equivalent to '/dev/null'. That is, if one does not need the output of a particular operation (and in our case it is an operation that creates a biggish file).
Eventually I ended up solving my problem the following way (answer tailored to MediaRecorder problem but can be generalized to other situations too):
fun MediaRecorder.setOutputFile(context: Context) {
val tmpRecordingFolder = File(context.filesDir, "tmp_media")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
setOutputFile(File(tmpRecordingFolder, "recording.mp3"))
} else {
setOutputFile("/dev/null")
}
}
Basically I am setting the output to be in the internal storage. I hope the file will not get huge and I am deleting the file in as many places in the code as possible. This seems to work on newer devices, currently have not yet ran into storage problems either, but the solution is not rolled out to production yet. Will update my answer if problems are identified.
I had the same issue, you'll have to specify a path since MediaRecorder crashes in Android 11 if you don't provide it, in order to avoid writing a massive file you could try to flush the file by stopping / restarting MediaRecorder, I been dealing with this issue for a few days too.
I replied a more detailed answer here: MediaRecorder Android 11 start failed -1004
Related
I am working on an app and one of the features I am working on is to download some binary files. Some of them are really big (more than several mega-bytes). Downloads are completing fine as long as the file size is less than 2 GB.
I got stuck on a file that is 3.2GB in that I get progress updates (I am pooling the DownloadManager for progress updates), but when the download completes, the file is not present on the target file path. Interrogating the DownloadManager for that download id, I get STATUS_FAILED and reason ERROR_UNKNOWN - the favorite error details one will ever wish for!
What is weird is that this appears on most of the devices, but for some (like Samsung SG 4 Active OS 4.2.2 and LG Nexus 5 OS 4.4.2), it doesn't appear.
Doing some extra investigation, I found out that this seems to be a bug in Android DownloadManager implementation. It seems Android implementation stores the download count as an int, but when that count goes above Integer.MAX_VALUE the download ends as failed.
I am thinking to replace the DownloadManager usage with a foreground service, but I wouldn't give up yet ....
Did you guys face this and if so, how did you fix it?
Is there any work-around to use DownloadManager in pre-4.2.2 so I can download more than 2.1 GB per file?
To download such a large files, you need to download those in chunks. Either you can use any library that support HTTP range options to allow to pull down a single file in multiple pieces , supporting resume etc.
Or you can split your large file on your server then have a text file with MD5 hash of each file, when you first start to download then get the MD5 file once finish then check that hashes matches the downloaded pieces. If they do not then delete that piece and add it to queue of items to download.
Once all pieces downloaded and MD5 works, you can put the pieces back together as single file.
If you are thinking to download the file in the SD card then FAT32 is the default file system. There is a 4 GB per file limit with this file system.
From looking at the Android source code, it appears that this issue was resolved in JB-MR2.
It seems that the only way to work around this on older platform versions would be to modify the server such that it uses chunked transfer encoding[1] for these large resources. In that case, that Download Manager will ignore and not attempt to parse the Content-Length header.
[1] http://en.wikipedia.org/wiki/Chunked_transfer_encoding
There is one clear outcome of this:
You can not fix the DownloadManager. If it's a bug in it, it will be so. Therefore, in short, No, you can not workaround this issue using the DownloadManager. You could however workaround it using a server side approach that has been put into words in the other answers.
So, I think your simplest solution would be to force the minimum sdk level to JB-MR2 because #ksasq mentioned that this issue has been resolved.
If that is not plausible nor in your case possible, you can find the best file download library out there and create an interface similar to DownloadManager's for this library. Of course, this interface should be implemented to use the default DownloadManager for versions which do not have this bug and use the custom library for those which had this bug (and for files who cause the issue if possible).
Unfortunately, a search on google showed yingyixu's android-download-manager last updated in 2012.
Another unfortunate note about this topic by CommonsWare simply verifies that there is no DownloadManager in google's support libraries. Worse is that the guy gave up the idea of implementing his own port becuase it was way too complicated. You can only hope that yingyixu's library or some other library you hopefully find is good enough.
You can pass this issue by splitting file into smaller zip files. Next step is to join them on target, I've found ->this<- that might help you. If you will not compress file (split only option) you should have good performance. Other issue is that you will need twice as much storage space. You can download smaller files, about 100MB, write it to joined buffer and remove form file-system, that will preserve space wasting.
You could also take the fixed version of DownloadManager, change the package to your package structure and use this version instead of the system version. Eventually you need to import some classes from the original package android.app. Then register your implementation as a service.
I have an issue with some devices. I cannot replicate it on any device but I have quite a lot of crash reports reported by some users.
It is this exception:
java.lang.IllegalArgumentException: Unknown URL content://media/external/file
at android.content.ContentResolver.delete(ContentResolver.java:1024)
I use this:
context.getContentResolver().delete(MediaStore.Files.getContentUri("external"),
MediaStore.Files.FileColumns.DATA + "=?", new String[] { path });
After that I call MediaScannerConnection.scanFile() on file's parent directory, because it is imho most functional way how to notify MediaScanner about deletion of file and how to refresh MTP content. I tried all other ways that I have found here on stackoverflow (e.g.Android How to use MediaScannerConnection scanFile) but nothing is working as well as this.
Btw. I use it only for APIs 11 and newer. External storage is certainly mounted.
I have these questions:
1. Do you know any reason why this exception occurs ? I don't want just to ignore the exception. And I don't want to remove this code when it works quite good for most devices.
2. Do you know some new reliable method how to notify MediaScanner and how to refresh immediately content of MTP when some file is deleted ?
Most probably it has to do with caching on the device. Catching the exception and ignoring is not nice but my problem was fixed and it seems to work.
I need to lock a text file that is read and written from three different android applications...so different processes.
I've tried to use channel lock() (exclusive mode) when writing and lock(0L, Long.MAX_VALUE, true) (shared) when reading the file.
Unfortunately this approach does not work...lock is always acquired when reading also when the writing lock is not yet released.
Are there suitable and working examples to solve this issue?
Am I doing something wrong?
Finally I've solved it!
FileLocks are ok...my problem is that I was writing to an xml file using storeToXml that probably creates a brand new file...so new file descriptor is created and the lock property was probably lost.
Now I'm locking another dummy file instead of the one I'm reading and writing and everything works as expected.
Since I upgraded my Galaxy S2 to Android 4 I am having some weird problem with my audio player application.
Since the upgrade MediaMetadataRetriever doesn't output much info other than the track number and the embedded picture. No title, no artist, pretty much nothing.
I am currently at a loss, as the problem is just made worse that the Android 4.0.3 emulator doesn't have the same problem.
Googling for this didn't help much, although I find it hard to imagine that I would be the only one with this kind of problem. My wife's SGS2 shows the same problem, so I don't expect it to be some strange problem limited to my phone.
Does anybody know if that might be a problem limited to ICS for the SGS2?
Did anybody else experience problems with MediaMetadataRetriever on ICS?
And, I guess most importantly, does anybody have a solution for this?
In case you want to check if my application has that problem on your phone you can get either code or APKs at http://www.sourceforge.net/projects/andrstoryteller
Any general advice on how I might be able to track down the problem would help as well.
I will test your sample application when I have a moment but in the meantime you may also want to think about another solution besides MediaMetadataRetriever since it limits your API compatibility and (apparently) doesn't always work. My project, ServeStream, uses a stripped down version of Apache Tika to retrieve the metadata. You may want to consider this approach in your own project. Here is a URL to the Tika jar and the class to do the parsing:
http://servestream.svn.sourceforge.net/viewvc/servestream/trunk/lib/tika-app-1.0.jar?view=log
http://servestream.svn.sourceforge.net/viewvc/servestream/trunk/src/net/sourceforge/servestream/utils/MetadataRetriever.java?revision=1033&view=markup
I noticed the same issue on ICS (On Galaxy SII and Galaxy Tab II both running ICS 4.0.3).
This seems to impact only mp3.
I guess one of the solutions as William suggested would be to use an external library but I also prefer to use what android offers rather then external libraries.
What bothers me is that I cannot find other posts reporting the same issue apart from this one. Though, I don't think I am doing it wrong:
I have tried two solutions:
MediaMetadataRetriever mmdr = new MediaMetadataRetriever();
mmdr.setDataSource(path);
String title = mmdr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
and
File file = new File(path);
FileInputStream inputStream;
inputStream = new FileInputStream(file);
mmdr = new MediaMetadataRetriever();
mmdr.setDataSource(inputStream.getFD());
inputStream.close();
String title = mmdr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
MediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) always retuns null.
The path is correct and the mp3 file does have the ID3 tag with the title and everything.
A solution that I thought of apart from using an external library would be to query the MediaStore on the file's path:
Cursor c = mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.MediaColumns.TITLE},
MediaStore.MediaColumns.DATA + "=?",
new String[] { path }, null);
String title;
if(c!=null && c.moveToFirst())
title = c.getString(c.getColumnIndex(MediaStore.MediaColumns.TITLE))
}
If the MediaScanner scanned it (it should have), the info should be there. This should also work for API levels before 10.
Basically, what I do in my project is the following: If SDK version is < 10 or the file's extension is mp3 and SDK version is 15, I query the MediaStore, otherwise I use MediaMetaDataRetriever.
A little update on the situation.
I have just put a couple of Ogg/Vorbis files onto my phone and there it can read the tags properly.
Will have to test with some more files, but maybe this has only stopped working for MP3 files.
Would be cool if I could get a couple of more people with ICS phones to test this.
Anyway, I'm currently looking into an alternative way to get this information, so I probably won't be using MediaMetadataRetriever for much longer.
I am still new to android programming, (wrote one small app so far) and I am also new to stack overflow. I am looking to write something that will listed for changes in a file, exactly like how file observer works. but the issue is the file im looking at receives changes from the kernel, and i realized that file observer does seem to pick up on changes unless it is done by the user. thanks.
I know this is old, but I figure I should Post the answer I found.
The solution is UEventObserver
doc: (http://www.androidjavadoc.com/1.1_r1_src/android/os/UEventObserver.html)
I found my answer in the "frameworks / base / services / java / com / android / server /" area of the android source code where they listen to changes reported form the kernel.
my implementation of the solution is here: https://github.com/gh123man/ICS_tablet_HW_rotationlock/blob/master/frameworks/base/services/java/com/android/server/RotationSwitchObserver.java
I believe there is no good solution. FileObserver will only report events that originate in user space - kernel originated events (i.e. to procfs file) are not reported. Further, the File operations won't work either, so you can can't check the hash, length, modified date, etc. of these files.
My observations are based on 2.3.6.
"the file im looking at receives changes from the kernel"
If you are referring to file from the procfs, or some other virtual-file, I fear inotify won't help you a lot...
search for "Q: Are there any limitations for use of inotify?"
Q: Are there any limitations for use of inotify?
Yes. Some filesystems (e.g. procfs or some network filesystems) don't emit
events in some cases.