0

I try to implement a gallery app which also shows all locally stored images files grouped by their containing directories. To this end I build upon the MediaStore API.

My code does not find local image directories, if these directories and the image files were created by Google Photos. But if I use Google Files, to copy/move/create an image file in the affected directory, then my app finds that image.

What am I doing wrong?

Note: I am talking about real filesystem directories below the Pictures/ directory on the externals storage. I am not talking about albums which Google Photos creates in the cloud. According to the developer documentation the MediaStore API should find all images below the Pictures/ directory.

Images, including photographs and screenshots, which are stored in the DCIM/ and Pictures/ directories. The system adds these files to the MediaStore.Images table.

Simplified code:

Manifest

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Simplified data class

public class LocalFolder {
  public final long id;
  public final Uri coverUri;

  public LocalFolder( final long id, final Uri coverUri ) {
    this.id = id;
    this.coverUri = coverUri;
  }
}

Simplified code to seed the internal database

protected TreeMap< Long, LocalFolder > database;

public void run() {
  final Uri collection = ( Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ) ?
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI :
    MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);

  final String[] projection = {
    MediaStore.Images.Media._ID,
    MediaStore.Images.Media.BUCKET_ID };
  final Cursor cursor = contentResolver.query(
    collection, projection, null, null, null
  );
  if(cursor == null) return;

  // Cache column indices
  final int imageIdColumn = cursor.getColumnIndexOrThrow( MediaStore.Images.Media._ID );
  final int folderIdColumn = cursor.getColumnIndexOrThrow( MediaStore.Images.Media.BUCKET_ID );

  while( cursor.moveToNext() ) {
    // Compile all required attributes
    final long imageId = cursor.getLong( imageIdColumn );
    final long folderId =  cursor.getLong( folderIdColumn );
    final Uri coverUri = ContentUris.withAppendedId( collection, imageId );

    // If the image is contained in a folder, which already has been processed, skip
    if( database.containsKey( folderId ) )
      continue;

    // Create the folder and take the current image as cover image
    final LocalFolder localFolder = new LocalFolder( folderId, coverUri );
    database.put( folderId, localFolder );
  }
  cursor.close();
}

Steps to reproduce:

  1. Create a new, shared image file
    1. Open your favorite web browser and download an image file
    2. The image file is put into the shared Downloads/ directory
  2. Above code finds the image (good!)
  3. Move image file into a new real, file-system based directory with Google Photos
    1. Open Google Photos
    2. Open the register "Library"
    3. Open the album "Downloads"
    4. Open the recently added image
    5. Tap "Settings" (thee dots in the upper right corner)
    6. Tap "Move to folder"
    7. Tap "New folder"
    8. Create a new folder
  4. Above code does not find the image (bad!)
  5. "Re-create" the image file using Google Files
    1. Open Google Files
    2. Tap hamburger menu
    3. Tap device
    4. Open the directory Pictures/
    5. Open the sub-directoy which corresponds to the newly created directory by Google Photos
    6. Long-tap the recently added image file
    7. Move the image file and move the image file back into the folder
  6. Above code finds the new folder and the image (good!)
user2690527
  • 1,729
  • 1
  • 22
  • 38
  • `My code does not find local image directories` What are local image directories? Please give full paths. – blackapps Mar 14 '21 at 17:49
  • Further tell the Android version of used devices. – blackapps Mar 14 '21 at 17:51
  • Further you are not showing how you query the MediaStore ... – blackapps Mar 14 '21 at 17:54
  • @blackapps Question 1+3 have already been answered in the post. I am running Android 11 on top of an AVD which simulates a Pixel 3a. – user2690527 Mar 14 '21 at 18:05
  • I did not look at your code yet or did the scenario but on an Android 11 device to let the MediaStore give you all files of other apps you need not only in manifest but at runtime let the user toggele a setting for it. There is an intent action to do so also. – blackapps Mar 14 '21 at 19:42
  • I believe you are erring. You presumably meant the `READ_EXTERNAL_STORAGE` permission. The app's manifest declares that permission and the main activity also asks for that permission at runtime. If the app had not that permission, the app would not show the image at all and not after the image has been moved by Google Files. I added the `READ_EXTERNAL_STORAGE` permission just for the sake of testing and also triggered the intent `Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION`. As expected it did change anything which is in line with the documentation. – user2690527 Mar 15 '21 at 17:55

0 Answers0