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.
Related
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
Ok This might seem like a dumb question but I'm not finding an answer.
I use to program for my old samsung S3. It's basically the device I learned to code for because it was all I had. But all the coding I was doing was old code I learned off Youtube etc.. as I'm self taught.
I recently invested in myself to learn some more modern code and to do things I couldn't do with my old equipment and I have run into trouble.
I have managed to fix some things like my retrofit and Picasso not working, because of a line of code missing in the manifest, but I am stuck when it comes to the Camera app as my code doesn't work on my pixel 3 but does work on my S3.
So I have a few questions that maybe someone can help answer for me.
so my 1st question is involving saving my pictures.
private File getfile () throws IOException {
File propicturefolder = new File("sdcard/camera_pro");
if (!propicturefolder.exists())
{
propicturefolder.mkdir();
}
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String prepend = "Picture_" + timestamp + "_";
File image_file = File.createTempFile(prepend, ".jpg", propicturefolder);
return image_file;
}
As you can see in my first bit of code I'm saving the picture to the SD card. But apparently a Pixel 3 doesn't have a SD card. So I don't know where to save it? There aren't really any examples out there that explain where this goes for a pixel 3. All my old examples go to the SD card.
I have tried to google an answer for this but nothing comes up but reviews of the Pixel 3 camera. What is the correct path that I am suppose to use?
My second question is this.
On my S3 I don't have to really ask for any permissions other than in the manifest so I'm trying to understand how this whole permission thing works. In the Manifest I have.
<uses-feature
android:name="android.hardware.camera2"
android:required="true" />
But in some of the example I am looking to learn permissions I see.
<uses-permission android:name="android.permission.CAMERA" />
Am I suppose to use both of these? I had learned Camera is outdated and Camera2 is what is used. Should that be android.permission.CAMERA2?
My camera doesn't work on my Pixel 3 but the code does work on my S3. So I need to learn how to code this differently apparently.
Google doesn't really give great examples on any of this. And the web is simply flooded with a lot of the wrong way to do things aka old ways.
If anyone can explain to me the changes on how this works on API 28 so I can learn how to add the slow motion camera etc or point me to an example that isn't out dated and made for android api 28 your help would be appreciated.
I'm an Android developer, and got a Nougat device recently, and noticed that a lot of the apps I've written crash on this device.
The crashes are traceable to FileUriExposedException, and I'm aware of the cause and fixes for this (targetSdkVersion < 24, FileProvider, content URIs, VmPolicy with StrictMode, etc.)
But I'm less clear on the big picture here. In my case, I have about a dozen apps that are interconnected, and they pass file URIs to each other. I can change them to the new standard, but doing so doesn't benefit me, and I also make use of old apps that I have no control over, and that don't know anything about content URIs.
I tried several file managers that I have, and noticed that an old version of ES File Explorer, and a new version of Mixplorer, both use file URIs when invoking apps, whereas Solid Explorer is using content URIs. So the situation appears to be very much up in the air.
I'm familiar with the Linux world, where it's possible to have either tight or loose file permissions. It's clear to me what the tight equivalent is on Nougat, but is there any equivalent of loose permissions? At the moment, my thought is to turn off the exception using the two-line StrictMode scheme, while gradually tweaking my applications in the desired direction, for example by handling both file and content URIs that are passed in.
Does anyone have thoughts on the bigger picture here?
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 a custom file format in res/raw, which means it will get compressed in APK.
Assume my application is installed on the device. When I open a file via openRawResource(), does it completely uncompress the file in the memory?
E.g. if it's a 3MB file, will it uncompress it in memory? If I only need 10KB data from a certain offset (and I reach it via BufferedInputStream.skip()), will it still consume 3MB when openRawResource() is called?
UPDATE: unless I'm overlooking something, it does not seem to be uncompressing the whole file. Consider the following test.
I added a 30MB file of random data to res/raw. Its extension is not ogg,mp3,png or similar, so it will be compressed in the APK. In the below code, I seek to around the 19MB-th position, and read cca. 117KB from the file. And it worked, even though the uncompressed length is 30MB. (As far as I read, the 1MB limit applies only to assets, not to raw resources.)
is = context.getResources().openRawResource(R.raw.test); // test is a 30MB test.txt
DataInputStream dis = new DataInputStream(new BufferedInputStream(is, 8192));
dis.skip(19555125);
byte[] testArr = new byte[117412];
dis.readFully(testArr);
for (int i = 0; i < testArr.length - 117000; i++) {
Log.w("LOG_TAG", "" + testArr[i]);
}
Yes, all "compressible" files are compressed. "Uncompressible" files
are certain image files, zip files, etc, that are already in a
compressed form and wouldn't benefit from compression.
Keep in mind the compression can be a problem, if you have a file larger
than 1M. The file will compress fine and the Android toolkit will
happily package it up, but on the phone it'll give an error when you
try to retrieve it, since the phone refuses to uncompress a file
larger than 1M. The workaround for this is to give the file an
extension of jpg or some such, so it doesn't get compressed
In the meantime, on the Android mailing list, Dianne Hackborn answered this question.
Quoting Dianne:
Prior to I think Gingerbread, it would entirely uncompress in memory
with a limit on the amount of memory it would use (I think 1MB) above
which the open would fail. On current versions of the platform it
uncompression is streamed as you read it with no limit on size.
My tests confirm this. I've just tested it on a Gingerbread and on an ICS device, and it works fine. In the upcoming days, I'll test it on a Froyo (Android 2.2) device as well, and will update this post.
Of course, Dianne is certainly right I'm sure, but she says she thinks "Gingerbread" is the first version where it's supported, so it won't hurt that I'll test it on Froyo then.
P.S.: thanks to CommonsWare for spotting the answer of Dianne.