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:
- Create a new, shared image file
- Open your favorite web browser and download an image file
- The image file is put into the shared Downloads/ directory
- Above code finds the image (good!)
- Move image file into a new real, file-system based directory with Google Photos
- Open Google Photos
- Open the register "Library"
- Open the album "Downloads"
- Open the recently added image
- Tap "Settings" (thee dots in the upper right corner)
- Tap "Move to folder"
- Tap "New folder"
- Create a new folder
- Above code does not find the image (bad!)
- "Re-create" the image file using Google Files
- Open Google Files
- Tap hamburger menu
- Tap device
- Open the directory Pictures/
- Open the sub-directoy which corresponds to the newly created directory by Google Photos
- Long-tap the recently added image file
- Move the image file and move the image file back into the folder
- Above code finds the new folder and the image (good!)