Question

I'm looking for: A list of the existing photo gallery names (hopefully their top thumbnail as well) The contents of the gallery (I can then load thumbnails and full size as needed)

How would I go about getting a list of the "Galleries" (don't know if that's the proper term in android for the groupings of images visible in the Gallery app...) and their contents? I need access to the gallery in it's structure without using the existing gallery display (I'm creating a totally new one, not an over layer to the photo requestor etc.)

I assume MediaStore.Images is where I need to be but I don't see anything that will give me the groupings...

Was it helpful?

Solution

Groupings are defined by MediaStore.Images.Media.BUCKET_DISPLAY_NAME. Here is the sample code to list the images and log their bucket name and date_taken:

// which image properties are we querying
String[] projection = new String[] {
        MediaStore.Images.Media._ID,
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
        MediaStore.Images.Media.DATE_TAKEN
};

// content:// style URI for the "primary" external storage volume
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

// Make the query.
Cursor cur = managedQuery(images,
        projection, // Which columns to return
        null,       // Which rows to return (all rows)
        null,       // Selection arguments (none)
        null        // Ordering
        );

Log.i("ListingImages"," query count=" + cur.getCount());

if (cur.moveToFirst()) {
    String bucket;
    String date;
    int bucketColumn = cur.getColumnIndex(
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME);

    int dateColumn = cur.getColumnIndex(
        MediaStore.Images.Media.DATE_TAKEN);

    do {
        // Get the field values
        bucket = cur.getString(bucketColumn);
        date = cur.getString(dateColumn);

        // Do something with the values.
        Log.i("ListingImages", " bucket=" + bucket 
               + "  date_taken=" + date);
    } while (cur.moveToNext());

}

OTHER TIPS

/**
 * Getting All Images Path
 * 
 * @param activity
 * @return ArrayList with images Path
 */
public static ArrayList<String> getAllShownImagesPath(Activity activity) {
    Uri uri;
    Cursor cursor;
    int column_index_data, column_index_folder_name;
    ArrayList<String> listOfAllImages = new ArrayList<String>();
    String absolutePathOfImage = null;
    uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

    String[] projection = { MediaColumns.DATA,
            MediaStore.Images.Media.BUCKET_DISPLAY_NAME };

    cursor = activity.getContentResolver().query(uri, projection, null,
            null, null);

    column_index_data = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
    column_index_folder_name = cursor
            .getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
    while (cursor.moveToNext()) {
        absolutePathOfImage = cursor.getString(column_index_data);

        listOfAllImages.add(absolutePathOfImage);
    }
    return listOfAllImages;
}

Here is the full solution in few simple steps:

The next few steps will guid you how to create a Vector that will hold the albums found on a given device. Every Album will hold a preview image as well an inner Vector that will hold all the images of the Album.

  1. Create an object that will hold the images once extracted from storage. We are going to call it PhoneAlbum. This is how it's going to look:

    public class PhoneAlbum {
    
        private int id;
        private String name;
        private String coverUri;
        private Vector<PhonePhoto> albumPhotos;
    
        public int getId() {
            return id;
        }
    
        public void setId( int id ) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName( String name ) {
            this.name = name;
        }
    
        public String getCoverUri() {
            return coverUri;
        }
    
        public void setCoverUri( String albumCoverUri ) {
            this.coverUri = albumCoverUri;
        }
    
        public Vector< PhonePhoto > getAlbumPhotos() {
            if ( albumPhotos == null ) {
                albumPhotos = new Vector<>();
            }
            return albumPhotos;
        }
    
        public void setAlbumPhotos( Vector< PhonePhoto > albumPhotos ) {
            this.albumPhotos = albumPhotos;
        }
    }
    
  2. Create an object that will hold the images within the album called: PhonePhoto

    public class PhonePhoto {
    
        private int id;
        private String albumName;
        private String photoUri;
    
        public int getId() {
            return id;
        }
    
        public void setId( int id ) {
            this.id = id;
        }
    
        public String getAlbumName() {
            return albumName;
        }
    
        public void setAlbumName( String name ) {
            this.albumName = name;
        }
    
        public String getPhotoUri() {
            return photoUri;
        }
    
        public void setPhotoUri( String photoUri ) {
            this.photoUri = photoUri;
        }
    }
    
  3. Create an interface to handle the extracted images upon completion. We are going to call it OnPhoneImagesObtained. Here it is:

    public interface OnPhoneImagesObtained {
    
        void onComplete( Vector<PhoneAlbum> albums );
        void onError();
    
    }
    
  4. Create a new class: DeviceImageManager

    public class DeviceImageManager {
    
    }
    
  5. Once you created DeviceImageManager, add the following method:

    public static void getPhoneAlbums( Context context , OnPhoneImagesObtained listener ){
        // Creating vectors to hold the final albums objects and albums names
        Vector< PhoneAlbum > phoneAlbums = new Vector<>();
        Vector< String > albumsNames = new Vector<>();
    
        // which image properties are we querying
        String[] projection = new String[] {
                MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
                MediaStore.Images.Media.DATA,
                MediaStore.Images.Media._ID
        };
    
        // content: style URI for the "primary" external storage volume
        Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    
        // Make the query.
        Cursor cur = context.getContentResolver().query(images,
                projection, // Which columns to return
                null,       // Which rows to return (all rows)
                null,       // Selection arguments (none)
                null        // Ordering
        );
    
        if ( cur != null && cur.getCount() > 0 ) {
            Log.i("DeviceImageManager"," query count=" + cur.getCount());
    
            if (cur.moveToFirst()) {
                String bucketName;
                String data;
                String imageId;
                int bucketNameColumn = cur.getColumnIndex(
                    MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
    
                int imageUriColumn = cur.getColumnIndex(
                    MediaStore.Images.Media.DATA);
    
                int imageIdColumn = cur.getColumnIndex(
                    MediaStore.Images.Media._ID );
    
                do {
                    // Get the field values
                    bucketName = cur.getString( bucketNameColumn );
                    data = cur.getString( imageUriColumn );
                    imageId = cur.getString( imageIdColumn );
    
                    // Adding a new PhonePhoto object to phonePhotos vector
                    PhonePhoto phonePhoto = new PhonePhoto();
                    phonePhoto.setAlbumName( bucketName );
                    phonePhoto.setPhotoUri( data );
                    phonePhoto.setId( Integer.valueOf( imageId ) );
    
                    if ( albumsNames.contains( bucketName ) ) {
                        for ( PhoneAlbum album : phoneAlbums ) {
                            if ( album.getName().equals( bucketName ) ) {
                                album.getAlbumPhotos().add( phonePhoto );
                                Log.i( "DeviceImageManager", "A photo was added to album => " + bucketName );
                                break;
                            }
                        }
                    } else {
                        PhoneAlbum album = new PhoneAlbum();
                        Log.i( "DeviceImageManager", "A new album was created => " + bucketName );
                        album.setId( phonePhoto.getId() );
                        album.setName( bucketName );
                        album.setCoverUri( phonePhoto.getPhotoUri() );
                        album.getAlbumPhotos().add( phonePhoto );
                        Log.i( "DeviceImageManager", "A photo was added to album => " + bucketName );
    
                        phoneAlbums.add( album );
                        albumsNames.add( bucketName );
                    }
    
                } while (cur.moveToNext());
            }
    
            cur.close();
            listener.onComplete( phoneAlbums );
        } else {
            listener.onError();
        }
    }
    
  6. Now all you have left is to render the images to screen. In my case I like to use Picasso. Here is how I do it:

        Picasso.with( getActivity() )
                    .load( "file:" + mPhoneAlbums.get( i ).getCoverUri() )
                    .centerCrop()
                    .fit()
                    .placeholder( R.drawable.temp_image )
                    .into( mAlbumPreview );
    
  7. Don't forget to add a permission to read external storage in your manifest:

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

That's it. You are good to go! Good luck!

Download the source code from here (Get all images from gallery in android programmatically)

activity_main.xml

<RelativeLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    xmlns:android="http://schemas.android.com/apk/res/android">


    <GridView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/gv_folder"
        android:numColumns="2"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"></GridView>


</RelativeLayout>

MainActivity.java

package galleryimages.galleryimages;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    public static ArrayList<Model_images> al_images = new ArrayList<>();
    boolean boolean_folder;
    Adapter_PhotosFolder obj_adapter;
    GridView gv_folder;
    private static final int REQUEST_PERMISSIONS = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gv_folder = (GridView)findViewById(R.id.gv_folder);

        gv_folder.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Intent intent = new Intent(getApplicationContext(), PhotosActivity.class);
                intent.putExtra("value",i);
                startActivity(intent);
            }
        });


        if ((ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) && (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
            if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) && (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.READ_EXTERNAL_STORAGE))) {

            } else {
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},
                        REQUEST_PERMISSIONS);
            }
        }else {
            Log.e("Else","Else");
            fn_imagespath();
        }



    }

    public ArrayList<Model_images> fn_imagespath() {
        al_images.clear();

        int int_position = 0;
        Uri uri;
        Cursor cursor;
        int column_index_data, column_index_folder_name;

        String absolutePathOfImage = null;
        uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

        String[] projection = {MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME};

        final String orderBy = MediaStore.Images.Media.DATE_TAKEN;
        cursor = getApplicationContext().getContentResolver().query(uri, projection, null, null, orderBy + " DESC");

        column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
        column_index_folder_name = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
        while (cursor.moveToNext()) {
            absolutePathOfImage = cursor.getString(column_index_data);
            Log.e("Column", absolutePathOfImage);
            Log.e("Folder", cursor.getString(column_index_folder_name));

            for (int i = 0; i < al_images.size(); i++) {
                if (al_images.get(i).getStr_folder().equals(cursor.getString(column_index_folder_name))) {
                    boolean_folder = true;
                    int_position = i;
                    break;
                } else {
                    boolean_folder = false;
                }
            }


            if (boolean_folder) {

                ArrayList<String> al_path = new ArrayList<>();
                al_path.addAll(al_images.get(int_position).getAl_imagepath());
                al_path.add(absolutePathOfImage);
                al_images.get(int_position).setAl_imagepath(al_path);

            } else {
                ArrayList<String> al_path = new ArrayList<>();
                al_path.add(absolutePathOfImage);
                Model_images obj_model = new Model_images();
                obj_model.setStr_folder(cursor.getString(column_index_folder_name));
                obj_model.setAl_imagepath(al_path);

                al_images.add(obj_model);


            }


        }


        for (int i = 0; i < al_images.size(); i++) {
            Log.e("FOLDER", al_images.get(i).getStr_folder());
            for (int j = 0; j < al_images.get(i).getAl_imagepath().size(); j++) {
                Log.e("FILE", al_images.get(i).getAl_imagepath().get(j));
            }
        }
        obj_adapter = new Adapter_PhotosFolder(getApplicationContext(),al_images);
        gv_folder.setAdapter(obj_adapter);
        return al_images;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            case REQUEST_PERMISSIONS: {
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults.length > 0 && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                        fn_imagespath();
                    } else {
                        Toast.makeText(MainActivity.this, "The app was not allowed to read or write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
                    }
                }
            }
        }
    }

}

I've found a way to get albums without iterating over every photo.

 String[] projection = new String[]{
                "COUNT(*) as count",
                MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
                MediaStore.Images.ImageColumns.DATA,
                "MAX (" + MediaStore.Images.ImageColumns.DATE_TAKEN + ") as max"};

 Context context = ServiceProvider.getInstance().getApplicationContext();
 Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                projection,
                "1) GROUP BY (" + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
                null,
                "max DESC");

cursor will contain as much elements, as distinct bucket name exists, and also you can get count inside every cursor position to get count of images inside album

here example:

if (cursor != null) {
            if (cursor.moveToFirst()) {
                do {
                //gets image path, it will always be a latest image because of sortOrdering by MAX date_taken
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                //gets count via alias ("as count" in projection)
                int count = cursor.getInt(cursor.getColumnIndex("count"));

                //do you logic here
                ...

                } while (cursor.moveToNext());
            }

            cursor.close();
        }

Some explanation about selection param:

contentResolver adds parentheses when compiling resulting query for sqlLite, so if we make selection like

"GROUP BY " + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME

it will be compiled as "WHERE (GROUP BY bucket_display_name)" and will cause SQLiteException at runtime. Otherwise if we make selection like

"1) GROUP BY (" + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME

it will be compiled as "WHERE (1) GROUP BY (bucket_display_name)", which is correct

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top