Android cooliris gallery developer documentation

Does anyone know how to integrate with the new Gallery3D app (cooliris android gallery)? I want to launch that app so it shows the thumbnails for only a specific folder.

For example, say my app downloads images from my server and stores them in a folder on the sd-card (/sdcard/myapp/image-cache/someid/*). I'd like to be able to do something like the following:

// within an activity
Uri uri = Uri.withAppendedPath(Media.EXTERNAL_CONTENT_URI, "myapp/image-cache/someid");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

Thanks.


ANSWERS:


I'm told you need to launch it like this:

Uri targetUri = Media.EXTERNAL_CONTENT_URI;
String folderPath = Environment.getExternalStorageDirectory().toString() + "/" + "testFolder";
int folderBucketId = folderPath.toLowerCase().hashCode();
targetUri = targetUri.buildUpon().appendQueryParameter("bucketId", folderBucketId).build();

Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

Further info:

Ensure that you have the right path (check trailing slashes etc). As a test, you can check if the bucket id that comes out from your method equals the bucket id in the database (which you can query for using the MediaProvider class).

What you are doing right now is passing the first image in that bucket, and gallery automatically shows other images in view, but the difference is that you are trying to view an image, not a bucket, which is why it doesn't show up in a thumbnail view.

As far as your MediaScanner issue goes, connect() is an async call, so you should do everything in the method onMediaScannerConnected in you implementation of the MediaScannerConnectionClient interface. You already implemented this interface for onScanCompleted, so you just need to put the logic there instead of polling the MediaScannerService to see if it has connected.


I tried Jeff's code as well. it appears that it only works in the old gallery and not in the new gallery3D.

Gallery3D is currently returning this in logcat:

E/CacheService(  503): Error finding album -280923911

and browsing the source for CacheService, I found this:

    if (albumData != null && albumData.length > 0) {
        DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
        try {
            final int numAlbums = dis.readInt();
            for (int i = 0; i < numAlbums; ++i) {
                final long setId = dis.readLong();
                MediaSet mediaSet = null;
                if (setId == bucketId) {
                    mediaSet = feed.getMediaSet(setId);
                    if (mediaSet == null) {
                        mediaSet = feed.addMediaSet(setId, source);
                    }
                } else {
                    mediaSet = new MediaSet();
                }
                mediaSet.mName = Utils.readUTF(dis);
                if (setId == bucketId) {
                    mediaSet.mPicasaAlbumId = Shared.INVALID;
                    mediaSet.generateTitle(true);
                    return;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Error finding album " + bucketId);
            sAlbumCache.deleteAll();
            putLocaleForAlbumCache(Locale.getDefault());
        }
    } else {
        Log.d(TAG, "No album found for album id " + bucketId);
    }

And since I'm getting the "Error finding album" error instead of the "No album found for album id", this means android is finding the album, but is running into an IOException somewhere in those lines. Is this then an android source problem?


Yeah. It is source problem in the CacheService.loadMediaSets.

The source is:

public static final void loadMediaSets(final Context context, final MediaFeed feed, final DataSource source,
        final boolean includeImages, final boolean includeVideos, final boolean moveCameraToFront) {
    // We check to see if the Cache is ready.
    syncCache(context);
    final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
    if (albumData != null && albumData.length > 0) {
        final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
        try {
            final int numAlbums = dis.readInt();
            for (int i = 0; i < numAlbums; ++i) {
                final long setId = dis.readLong();
                final String name = Utils.readUTF(dis);
                final boolean hasImages = dis.readBoolean();
                final boolean hasVideos = dis.readBoolean();
                MediaSet mediaSet = feed.getMediaSet(setId);
                if (mediaSet == null) {
                    mediaSet = feed.addMediaSet(setId, source);
                } else {
                    mediaSet.refresh();
                }
                if (moveCameraToFront && mediaSet.mId == LocalDataSource.CAMERA_BUCKET_ID) {
                    feed.moveSetToFront(mediaSet);
                }
                if ((includeImages && hasImages) || (includeVideos && hasVideos)) {
                    mediaSet.mName = name;
                    mediaSet.mHasImages = hasImages;
                    mediaSet.mHasVideos = hasVideos;
                    mediaSet.mPicasaAlbumId = Shared.INVALID;
                    mediaSet.generateTitle(true);
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Error loading albums.");
            sAlbumCache.deleteAll();
            putLocaleForAlbumCache(Locale.getDefault());
        }
    } else {
        if (DEBUG)
            Log.d(TAG, "No albums found.");
    }
}

Reading of (hasImages and hasVideos) from the album metadata is missing. Putting two lines

 dis.getBoolean(); 
   dis.getBoolean(); 

in the loop after mediaSet.mName = Utils.readUTF(dis); will solve the problem, but nobody will do it.

So, obviously, because of the bug in the source code it is impossible to display specified bucket (directory) in the Gallery. :(


I wasn't able to get the thumbnail view for a folder working. Instead, I managed something almost as good by launching the gallery on the first image in the folder.

Here's a description of what I wanted to accomplish. A user selects a specific record from a list view. This record can have a few images associated with it. I wanted to be able to browse these images using the cool Gallery3D app on the Nexus One (now with multitouch zoom!). If the images for that record are not already cached on the device's sdcard I'll download them as a zip file. I then extract that file to a cache dir for that record on the sdcard. Afterwards, I wanted to launch the gallery and only display the images in that cache dir.

Performing the download and extracting the zip file to the sdcard was not a problem. But, in order to get the gallery working, I had to use the MediaScannerConnection with a MediaScannerConnectionClient. After getting the scanner to connect (which was kind of flakey), I looped through all the files in the cache dir calling scanner.scanFile.

The MediaScannerConnectionClient#onScanCompleted would append the resulting uri's to an ArrayList member variable. When the whole process was done I'd launch the gallery passing the first uri in that list. This would view the first image in the directory. I would've preferred the thumbnail view but this is good enough.

I'm not totally comfortable with this solution. It seems that the MediaScannerConnection works asynchronously so my AsyncTask does a poll/sleep to see if it's done scanning.

Has anyone else had issues with the MediaScannerConnection not connecting on the first call? To work around this I'm doing something like:

MediaScannerConnection scanner = ...;
for (int attempts = 0; attempts < MAX_ATTEMPTS; attempts++) {
  scanner.connect();
  if (scanner.isConnected()) { break; }
  else {
    try { Thread.sleep(5); }
    catch (Exception e){}
  }
}

if (!scanner.isConnected()) {
  throw new IllegalStateException("Unable to establish media scanner connection!");
}

Ugly I know but I'm not sure why it has trouble connecting the first time. :-/

UPDATE: Thanks to jeffamaphone, I was able to dump that ugly code. Now the OnItemClickListener just calls scanner.connect(). The client that is passed to the scanner's constructor initializes the DownloadAsyncTask which updates a ProgressDialog as it unzips the files and calls scanner.scanFiles(...);



 MORE:


 ? how to start building cooliris in openGL and C++?
 ? which tools to use for designing cooliris type applications?
 ? Google Chrome: JavaScript Error Message
 ? Google Chrome: JavaScript Error Message
 ? Google Chrome: JavaScript Error Message
 ? Unable to remove the textbox using javascript
 ? Input button image - not work in Chrome & Safari?
 ? Input button image - not work in Chrome & Safari?
 ? Input button image - not work in Chrome & Safari?
 ? How to change an input button image using CSS?