Android MediaMetadataRetriever fails to load metadata on old Samsung devices - android

I'm facing a strange issue when using the android.media.MediaMetadataRetriever. It fails to extract the video width from video files on Samsung phones with Android version 4.0.4 and 4.1.2. The call metaRetriever.extractMetadata() seems to return either null or an empty string, as users of my app are reporting the VideoSetupException with error code ASVF_3.
It works on the Google emulators with said Android versions and all other Android versions and devices.
Any idea what might be causing this? It seems to me that there is a bug in the Android version distributed by Samsung.
Thanks a lot.
M.
private void setVideoViewDimensionToMatchVideoMetadata(VideoView videoView, Uri uri) {
String metadataVideoWidth;
String metadataVideoHeight;
try {
final MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(getActivity(), uri);
metadataVideoWidth = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
metadataVideoHeight = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
metaRetriever.release();
} catch (NullPointerException | IllegalArgumentException ex) {
throw new VideoSetupException(getActivity().getString(R.string.ASVF_2)
+ StringUtils.SPACE + ex.getLocalizedMessage(), ex);
}
if (StringUtils.isEmpty(metadataVideoWidth)) {
throw new VideoSetupException(getActivity().getString(R.string.ASVF_3));
}

Related

ALBUM_ART column is deprecated from API 29 and so on, how to obtain path?

We are currently obtaining the path of album art using: MediaStore.Audio.AlbumColumns.ALBUM_ART, and is successfully obtaining the path, except on pixel 3a (Android 10). After some research, the ALBUM_ART became deprecated API 29 and over as shown: Here
In this link it says: "Apps may not have file system permissions to directly access this path. Instead of trying to open this path directly, apps should use ContentResolver#loadThumbnail to gain access."
My questions are:
1) I'm already stating on the application manifest the permissions for external storage access (READ_EXTERNAL_STORAGE) and is requesting permission while navigating in-app. Which permissions do i have to provide to allow access to album art in order to obtain the path?
2) I can't seem to find any content on loadThumbnail online (and not even on ContentResolver class through code, while i am using target and compile SDK 29), if 1) can't be done, then how do i use loadThumbnail and why it's not showing on code?
Thanks in advance.
In order to use the method of ContentResolver, make sure you have the latest SDK and relevant tools installed, and in your code first instantiate a ContentResolver object and then use it accordingly:
public class MainActivity extends AppCompatActivity {
public ContentResolver resolver;
Bitmap albumArt;
Size size;
Uri uriOfItem;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resolver = new ContentResolver(this) {
#NonNull
#Override
public Bitmap loadThumbnail(#NonNull Uri uri, #NonNull Size size, #Nullable CancellationSignal signal) throws IOException {
return super.loadThumbnail(uri, size, signal);
}
};
//uriOfItem = uri of your file
size = new Size(100, 100);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
try {
albumArt = resolver.loadThumbnail(uriOfItem, size, null);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
EDIT: when it comes to your first question if #Rj_Innocent_Coder doesn't mind me including his comment here:
As part of the scoped-storage feature on Android Q, Google announced that SAF (storage access framework) will replace the normal storage permissions. This means that even if you will try to use storage permissions, it will only grant to access to specific types of files for File and file-path to be used
EDIT 2: after #hetoan2 's comment I check the documentation again and I noticed that ContentResolver is abstract hence not being able to use ContentResolver.loadThumbnail() as a method call. That means that within an activity you could simply use the following as well:
Bitmap albumArt = getContentResolver().loadThumbnail(uriOfFile, sizeOfAreaThatDisplaysThumbnail, cancellationSignalOrNull);
For someone else who is having issues here, this is the solution that worked for me:
if(android.os.Build.VERSION.SDK_INT >= 29)
{
val album = "Name Of Album"
val artist = "Name of Artist"
// Determine album ID first
val cursor = context.contentResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
MediaStore.Audio.Albums.ALBUM_ID,
"${MediaStore.Audio.Albums.ALBUM} = '$album' AND
${MediaStore.Audio.Albums.ARTIST} = '$artist'"
,null,null)
val uri = if(cursor != null && cursor.count > 0)
{
cursor.moveToFirst()
ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, cursor.getString(0).toLong())
}
else
{
// Dummy URI that will not return an image
// If you end up here, the album is not in the DataStore
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI
}
val bm = try
{
// Set size based on size of bitmap you want returned
context.contentResolver.loadThumbnail(uri, Size(50,50), null)
}
catch(e: java.lang.Exception)
{
// Return default image indicating no image available from DataStore
BitmapFactory.decodeResource(context.resources, R.drawable.no_image)
}
}
try this it will work and load with glide imageView
int thumbColumn = audioCursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID);
int _thumpId = audioCursor.getInt(thumbColumn);
imgFilePath = "content://media/external/audio/albumart/"+_thumpId;
audioCursor.moveToPosition(i);
Glide.with(getContext()).load(imgFilePath).placeholder(R.drawable.missed).into(tracksAlbumArt);
Update Andriod Studio latest 4.2.X and targetSdkVersion to 30

Missing Meta data in com.googlecode.libphonenumber:libphonenumber:8.8.2 while building signed APK

I added com.googlecode.libphonenumber:libphonenumber:8.8.2 in my project. In debug mode its works normally.But in signed apk its generating the following exception when a library method is called.
Caused by: java.lang.IllegalStateException: missing metadata: /com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BD
at com.google.i18n.phonenumbers.e.getMetadataFromSingleFileName(SourceFile:188)
at com.google.i18n.phonenumbers.e.getMetadataFromMultiFilePrefix(SourceFile:116)
at com.google.i18n.phonenumbers.g.getMetadataForRegion(SourceFile:64)
at com.google.i18n.phonenumbers.PhoneNumberUtil.getMetadataForRegion(SourceFile:2211)
at com.google.i18n.phonenumbers.PhoneNumberUtil.getMetadataForRegionOrCallingCode(SourceFile:1330)
at com.google.i18n.phonenumbers.PhoneNumberUtil.parseHelper(SourceFile:3197)
at com.google.i18n.phonenumbers.PhoneNumberUtil.parse(SourceFile:3025)
at com.google.i18n.phonenumbers.PhoneNumberUtil.parse(SourceFile:3015)
at com.revesoft.itelmobiledialer.util.aq.b(SourceFile:697)ode here
Probably you have already fixed it, but it may help others. I had the same issue and I have fixed it as the library FAQs - How do I load libphonenumber resources in my Android app?
A possible problem can be that you are loading the metadata from the main thread. If this is not the case, then
you can copy the data folder with the metadata in your app. Create an assets folder src/main/assets/data.
In your application where you first want to read the data, create your own metadata loader that will read the metadata from its new destination. This is described in the link that I posted. The library FAQs suggest to delete the metadata files from the library in order not to duplicate files.
private static PhoneNumberUtil getPhoneNumberUtilInstance()
{
if(mPhoneNumberUtil == null)
{
mPhoneNumberUtil = PhoneNumberUtil.createInstance(new MetadataLoader()
{
#Override
public InputStream loadMetadata(String metadataFileName)
{
try
{
String[] stringPieces = metadataFileName.split("/");
String metadataName = stringPieces[stringPieces.length - 1];
InputStream is = Factory.get().getApplicationContext().getAssets().open("data/" + metadataName);
return is;
}
catch (IOException e)
{
// Handle somehow!
return null;
}
}
});
}
return mPhoneNumberUtil;
}

Android 4.4.2 crash during picking image

During developing application in Xamarin Android we encountered strange error. The pick image/video (whether its from camera or documents UI) application sometimes crashes with no error. Scenario is that we open application, make steps to the activity, where the images are chosen, and then open the camera or document UI by standard way:
public void ChooseMediaAfterTypeChose (bool photo, bool camera) {
try {
string title = "";
int id;
Intent iIntent;
if (camera) {
if (photo) {
iIntent = new Intent("android.media.action.IMAGE_CAPTURE");
id = Const.AND_pickImageID_camera;
App._file = new File (App._dir, "myPhoto.jpg");
iIntent.PutExtra (Android.Provider.MediaStore.ExtraOutput, Uri.FromFile (App._file));
} else {
iIntent = new Intent("android.media.action.VIDEO_CAPTURE");
id = Const.AND_pickVideoID_camera;
App._file = new File (App._dir, "myVideo.mp4");
iIntent.PutExtra (Android.Provider.MediaStore.ExtraOutput, Uri.FromFile (App._file));
}
} else {
iIntent = new Intent ();
iIntent.SetAction (Intent.ActionGetContent);
if (photo) {
iIntent.SetType ("image/jpg");
title = Static.mainData.currentTexts.ChoosePhoto;
id = Const.AND_pickImageID_galery;
} else {
iIntent.SetType ("video/mp4");
title = Static.mainData.currentTexts.ChooseVideo;
id = Const.AND_pickVideoID_galery;
}
}
if (camera) {
StartActivityForResult (iIntent, id);
} else {
StartActivityForResult (Intent.CreateChooser (iIntent, title), id);
}
} catch (Exception ex) {
ShowError (Static.mainData.currentTexts.MediaError);
W.L(ex.Message);
}
}
The chosen application crashes during image/video picking (E.g. during browsing images in gallery wthout picking any). When that happens we never get to any method in our code.
What we have:
When user don't pick photos, the application runs without any memory crash
Sometimes the picking proceedes without error.
We think that the issue is mainly on Android 4.4.2 (It happend to us only on devices with this android - on other android version devices we didn't encounter it)
What we tried:
We put all permissions to manifest (read/write external storage, hardware.camera etc.)
We delete almost all memory stored content to save up memory
All Activities are unload from memory when they leave the screen
Logcat says that every process connected (Application and the active application) just died with no trace to any error
Our question is if anyone stumbled to similar issue and how to handle it. The second question is if there is any way to find out whats happening.
EDIT:
App._dir code added.
App._dir = new Java.IO.File (
Environment.GetExternalStoragePublicDirectory (
Environment.DirectoryPictures), "Camera");
if (!App._dir.Exists ())
{
App._dir.Mkdirs( );
}

unable to load owl file to android project using owl api

I have been trying to load an OWL file that I made in Protégé. I import OWL API 3.4.3 to my project and also passed the sample.owl file to raw folder, but when I try to load the OWL file, it doesn't work. There was no error but I am just getting this message
unfortunately, sampleproject has stopped
Here is the section of code am using. When I try the code in a standard Java environment it works without a problem.
OWLOntology localOntology = null;
int rID = resources.getIdentifier("com.example.cammclient1:raw/"+"sample", null, null);
InputStream input = resources.openRawResource(rID);
OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
ontology = manager.loadOntologyFromOntologyDocument(input);
try {
for (OWLClass cls : localOntology.getClassesInSignature()) {
Log.d("class in the ontology", ((CharSequence) cls).toString());
}
TV1.setText("reading classes...............");
}
catch (Exception e) {
TV1.setText("Not successfull");
}
You are casting OWLClass instances to CharSequence and then calling toString() on it.
This will cause ClassCastException to be thrown - an OWLClass is not a string.
Just use cls.toString() instead, you will have the same result.
You are also swallowing the exception in the catch block. That's not helpful in diagnosing the issue, as it hides information by just saying "Not successful" without providing more information.

Copy the shared preferences XML file from /data on Samsung device failed

There's an exporting feature in my application. It's just a copy operation since all my settings are store in shared preference.
I just copy the xml file from /data/data/package.name/shared_prefs/settings.xml to SD card. It works fine on my HTC desire. However, it might not work on Samsung devices, and i got the following error while I try to copy the file.
I/System.out( 3166): /data/data/package.name/shared_prefs/settings.xml (No such file or directory)
in the directory.
Anyone know how to fix it, or is there another simple way to store the shared preference ?
Thanks.
Never never never never never never never never never hardwire paths.
Unfortunately, there's no getSharedPreferenceDir() anywhere that I can think of. The best solution I can think of will be:
new File(getFilesDir(), "../shared_prefs")
This way if a device manufacturer elects to change partition names, you are covered.
Try this and see if it helps.
CommonsWare's suggestion would a be clever hack, but unfortunately it won't work.
Samsung does not always put the shared_prefs directory in the same parent directory as the getFilesDir().
I'd recommend testing for the existence of (hardcode it, except for package name):
/dbdata/databases/<package_name>/shared_prefs/package.name_preferences.xml and if it exists use it, otherwise fall back to either CommonsWare's suggestion of new File(getFilesDir(), "../shared_prefs") or just /data/data/<package_name>/shared_prefs/package.name_preferences.xml.
A warning though that this method could potentially have problems if a user switched from a Samsung rom to a custom rom without wiping, as the /dbdata/databases file might be unused but still exist.
More details
On some Samsung devices, such as the Galaxy S series running froyo, the setup is this:
/data/data/<package_name>/(lib|files|databases)
Sometimes there's a shared_prefs there too, but it's just Samsung's attempt to confuse you! Don't trust it! (I think it can happen as a left over from a 2.1 upgrade to 2.2, but it might be a left over from users switching roms. I don't really know, I just have both included in my app's bug report interface and sometimes see both files).
And:
/dbdata/databases/<package_name>/shared_prefs
That's the real shared_prefs directory.
However on the Galaxy Tab on Froyo, it's weird. Generally you have: /data/data/<package_name>/(lib|shared_prefs|files|databases)
With no /dbdata/databases/<package_name> directory, but it seems the system apps do have:
/dbdata/databases/<package_name>/yourdatabase.db
And added bonus is that /dbdata/databases/<package_name> is not removed when your app is uninstalled. Good luck using SharedPreferences if the user ever reinstalls your app!
Try using
context.getFilesDir().getParentFile().getAbsolutePath()
Best way to get valid path on all devices - run method Context.getSharedPrefsFile defined as:
/**
* {#hide}
* Return the full path to the shared prefs file for the given prefs group name.
*
* <p>Note: this is not generally useful for applications, since they should
* not be directly accessing the file system.
*/
public abstract File getSharedPrefsFile(String name);
Because of it hidden need use reflection and use fallback on fail:
private File getSharedPrefsFile(String name) {
Context context = ...;
File file = null;
try {
if (Build.VERSION.SDK_INT >= 24) {
try {
Method m = context.getClass().getMethod("getSharedPreferencesPath", new Class[] {String.class});
file = (File)m.invoke(context, new Object[]{name});
} catch (Throwable e) {
Log.w("App TAG", "Failed call getSharedPreferencesPath", e);
}
}
if (file == null) {
Method m = context.getClass().getMethod("getSharedPrefsFile", new Class[] {String.class});
file = (File)m.invoke(context, new Object[]{name});
}
} catch (Throwable e) {
Log.w("App TAG", "Failed call getSharedPrefsFile", e);
file = new File(context.getFilesDir(), "../shared_prefs/" + name + ".xml");
}
return file;
}
On some Samsungs implements like this:
public File getSharedPrefsFile(String paramString) {
return makeFilename(getPreferencesDir(), paramString + ".xml");
}
private File getPreferencesDir() {
synchronized (this.mSync) {
if (this.mPreferencesDir == null) {
this.mPreferencesDir = new File("/dbdata/databases/" + getPackageName() + "/", "shared_prefs");
}
File localFile = this.mPreferencesDir;
return localFile;
}
}
On other Android like this:
public File getSharedPrefsFile(String name) {
return makeFilename(getPreferencesDir(), name + ".xml");
}
private File getPreferencesDir() {
synchronized (mSync) {
if (mPreferencesDir == null) {
mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
}
return mPreferencesDir;
}
}
private File getDataDirFile() {
if (mPackageInfo != null) {
return mPackageInfo.getDataDirFile();
}
throw new RuntimeException("Not supported in system context");
}
After while Google change API for level 24 and later:
https://android.googlesource.com/platform/frameworks/base/+/6a6cdafaec56fcd793214678c7fcc52f0b860cfc%5E%21/core/java/android/app/ContextImpl.java
I've tested in Samsung P1010 with:
//I'm in a IntentService class
File file = this.getDir("shared_prefs", MODE_PRIVATE);
I got:
"/data/data/package.name/app_shared_prefs"
It works fine to me. I can run ffmpeg in this folder.
Look:
Context.getDir
You have to create the shared_prefs directory:
try{
String dir="/data/data/package.name/shared_prefs";
// Create one directory
boolean success = (new File(dir)).mkdirs();
if (success) {
// now copy the file
}
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
Also... the package of your app is package.name? Make sure you are referring to the right package.

Categories

Resources