Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 11 Media store - cannot record new videos on relative path. It works with Environment.DIRECTORY_MOVIES path but not not with sub folder

My code runs perfect on any Android lower then Android 11. On Android 11 (specifically on Pixel2 & Pixel3 emulator and real devices) the file descriptor fail to find the file after inserting it to the media store.

If I change the relative path on the second line to be only the Environment.DIRECTORY_MOVIES path - it works

String relativeLocation = Environment.DIRECTORY_MOVIES;

This is my code:

String mimeType = "video/mp4";
String relativeLocation = Environment.DIRECTORY_MOVIES + File.separator + SUB_DIRECTORY_NAME ;
shortFileName = getDateStamp() + selectedExtension;
videoContentValues = new ContentValues();
videoContentValues.put(MediaStore.Video.Media.TITLE, shortFileName);
videoContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, shortFileName);
videoContentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
videoContentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
videoContentValues.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());

videoContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
videoContentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
videResolver = mContext.getContentResolver();

Uri contentUri = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
videoUri = videResolver.insert(contentUri, videoContentValues);
if (videoUri == null) {
    throw new IOException("Failed to create new MediaStore record.");
}
pfd = mContext.getContentResolver().openFileDescriptor(videoUri, "w");
mMediaRecorder.setOutputFile(pfd.getFileDescriptor());

The code runs OK until it gets to the openFileDescriptor which return the following error:

java.io.FileNotFoundException: java.io.FileNotFoundException: No item at content://media/external_primary/video/media/47

What am I doing wrong?

Update 1: More info: I am still requesting WRITE_EXTERNAL_STORAGE and making sure it is allowed before start recording

The following code works in the same camera app on Android 11 Pixel 2 emulator to save pics:

    String mimeType = "image/jpeg";
    final String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + SUB_DIRECTORY_NAME;
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, createImageFileNameQ());
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);
    ContentResolver resolver = mContext.getContentResolver();
    OutputStream stream = null;
    Uri uri = null;
    try {
          final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
          uri = resolver.insert(contentUri, contentValues);
      try {
                OutputStream fos = resolver.openOutputStream(uri);
                fos.write(data);
                fos.flush();
                    fos.close();
           }
     catch (Exception ex) {
        Log.e(TAG, ex.toString());
      }

Update 2:

If I write on the second line "String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + SUB_DIRECTORY_NAME;" and not DIRECTORY_MOVIES : It works!@!! Video files are saved on Videos\Sub_Directory

Update 3: Now on the emulators:

no trick helps to make relative path. And also the pics cannot be saved to relative path

String mimeType = "image/jpeg"; String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + SUB_DIRECTORY_NAME;
ContentValues contentValues = new ContentValues();
    
 contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, createImageFileNameQ());
  contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
  contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);

  ContentResolver resolver = mContext.getContentResolver();


  OutputStream stream = null;
  Uri uri = null;

  try {
    final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
     uri = resolver.insert(contentUri, contentValues);
 try {
     OutputStream fos = resolver.openOutputStream(uri);
     fos.write(data);
     fos.flush();
     fos.close();
 } catch (Exception ex) {
 Log.e(TAG, ex.toString());
 }
 } catch (Exception e) {}
like image 272
kfir Avatar asked Oct 15 '22 00:10

kfir


1 Answers

I have opened a ticket to Google/Android with full recording of the emulator debug messages like they asked. they said: "interesting, they will look into it". they did not answer - but they have fixed it for the latest Android 11 release. Security patch Nov. 2020. So - problem was solved. I have left a bug fix in my code in case somebody did not get the last android 11 update. In case of this error - I set IsAndroid11SaveOnSubDirectoryEnabled variable to false

String relativeLocation = Environment.DIRECTORY_MOVIES + File.separator + SUB_DIRECTORY_NAME;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q && IsAndroid11SaveOnSubDirectoryEnabled == false)
{
relativeLocation = Environment.DIRECTORY_MOVIES + File.separator + "$" + SUB_DIRECTORY_NAME;
Log.e(TAG, "Recording on $SubDirectory");
}

Edit II: I got an answer from Google/Android that maybe I have a ".nomedia" file in the directory, and so - the Media store cannot insert/index new files. (.nomedia is a file that tells the gallery not to read the medias on this folder, it applies until Android 10, on Android 11 - this file cannot be created or deleted in the movies folder because it is not media). But it was not correct - the log files and recording that I have sent to Google/Android were from an Android 11 Emulator which did not have this file.

Edit III - Since Dilijeet asked, IsAndroid11SaveOnSubDirectoryEnabled is a boolean that I save to the SharedPreference. here is the code - whenever the recording crash on IOExcpetion & Android 11 - I assume it is the subdirectory problem, and set this boolean for further recordings.

catch (IOException ex)
{

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && IsAndroid11SaveOnSubDirectoryEnabled == true) {
    mSharedPreferences.edit().putBoolean("chkSaveOnSubDirectory", false).apply();
    IsAndroid11SaveOnSubDirectoryEnabled = false;    
}
like image 85
kfir Avatar answered Oct 27 '22 01:10

kfir