2

I'm working on an application where the user is able to select files, either a new image from the camera, an image from the gallery, or a plain old file. It then shows an icon and the name for the selected item. I have this working with one exception. The gallery application integrates picasaweb pictures. If the user selects a picture from a picasa album, I'm not able to get a thumbnail for it.

I'm using the MediaStore.Images.Thumbnails.getThumbnail() method, and it works for other images in the gallery just fine, but for the picasaweb files, I get, regardless of what "kind" of thumbnail I attempt to get (although MICRO is what I'm after):

ERROR/MiniThumbFile(2051): Got exception when reading magic, id = 5634890756050069570, disk full or mount read-only? class java.lang.IllegalArgumentException

I noticed the URI's given for the selected files are different. The local image files look like:

content://media/external/images/media/6912

and the picasaweb urls look like:

content://com.android.gallery3d.provider/picasa/item/5634890756050069570

I attempted to use a query to get at the raw THUMB_DATA, using Thumbnails.queryMiniThumbnails(), with Thumbnails.THUMB_DATA in the projection array, but I got a "no such column" error.

Is there another method for getting thumbnails that would work better? And will I have the same problem when I try and access the full image data?

Mark
  • 2,362
  • 18
  • 34
  • I can easily determine the differences in the URI, and display a Toast if the image comes from picasa, but that's not exactly ideal. Better, but still not perfect, would be to exclude picasa images from the ACTION_PICK, but I can't see how to do that either. – Mark Oct 24 '11 at 18:01
  • I created an issue for this in the Android bug tracker. http://code.google.com/p/android/issues/detail?id=21234&q=picasa&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars – Mark Nov 22 '11 at 02:31

2 Answers2

2

What I have found is that on my Galaxy Nexus, the images for Picassa are stored in one of subdirectories under the /sdcard/Android/data/com.google.android.apps.plus/cache directory. When the content provider is com.google.android.gallery3d.provider then the number after "item" in the URL contains the name of the image (in your example above "5634890756050069570"). This data correspondes to a file in one of the subdirectories under /sdcard/Android/data/com.google.android.apps.plus/cache with the extension ".screen". If you were to copy this image from your phone (in your case 5634890756050069570.screen) using DDMS and rename it with the extension ".jpeg" you could open it and view it on your computer.

The following onActivityResult method will check for this content provider being returned, and then will recursively search for the file in the /sdcard/Android/data/com.google.android.apps.plus/cache directory. The private member variable fileSearchPathResults is filled in by the recursive search method walkDirectoryRecursivelySearchingForFile().

private String fileSearchPathResult = null;

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Uri selectedImage = data.getData();
            String[] filePathColumn = { MediaStore.Images.Media.DATA };
            String filePath = null;

            // This code is required to get the image path on content providers
            // on API > 10 where the image is from a picassa web album, since Google changed
            // the content provider in versions with API > 10
            if (selectedImage.toString().contains("com.google.android.gallery3d.provider")) {
                StringBuilder contentProviderPath = new StringBuilder(selectedImage.toString());
                int beginningIndex = contentProviderPath.lastIndexOf("/");
                String fileNameWithoutExt = contentProviderPath.subSequence(beginningIndex + 1,
                        contentProviderPath.length()).toString();
                Log.i(TAG, fileNameWithoutExt);
                try {
                    File path = new File("/sdcard/Android/data/com.google.android.apps.plus/cache");
                    if (path.exists() && path.isDirectory()) {
                        fileSearchPathResult = null;
                        walkDirectoryRecursivelySearchingForFile(fileNameWithoutExt, path);
                        if (fileSearchPathResult != null) {
                            filePath = fileSearchPathResult;
                        }
                    }
                } catch (Exception e) {
                    Log.i(TAG, "Picassa gallery content provider directory not found.");
                }
            }
    }


    public void walkDirectoryRecursivelySearchingForFile(String fileName, File dir) {
        String pattern = fileName;

        File listFile[] = dir.listFiles();
        if (listFile != null) {
            for (int i = 0; i < listFile.length; i++) {
                if (listFile[i].isDirectory()) {
                    walkDirectoryRecursivelySearchingForFile(fileName, listFile[i]);
                } else {
                    if (listFile[i].getName().contains(pattern)) {
                        fileSearchPathResult = listFile[i].getPath();
                    }
                }
            }
        }
    }

With the filePath, you can create a Bitmap of the image with the following code:

        Bitmap sourceImageBitmap = BitmapFactory.decodeFile(filePath);
donward_peng
  • 136
  • 5
  • I was having problems finding Picasa files on my Galaxy Nexus, and this solution worked for me. Thank you. But the reference to the google strings seems kind of brittle. Will it work on other phones? And is there a more general solution that doesn't depend on these particular hard-coded strings?? – gcl1 Sep 19 '12 at 19:16
  • This works, but the problem is this buffer area can be in different areas. AFAIK, this new content provider was added by Google to provide more security to your Picasa images. Your app gets a one-time-use use exception when reading the URL. Then the next time, you app will blow up if you use the URL again. If you need more use of the images, you have to make your own copy of it into your own caching area (though that opens up more security holes if your area is public). – kenyee Apr 15 '13 at 16:29
0

ACTIVITYRESULT_CHOOSEPICTURE is the int you use when calling startActivity(intent, requestCode);

public void onActivityResult(int requestCode, int resultCode, Intent data) {
  if(requestCode == ACTIVITYRESULT_CHOOSEPICTURE) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    final InputStream is = context.getContentResolver().openInputStream(intent.getData());
    final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
    is.close();
  }
}

That code will load the whole image. You can adjust the sample size to something reasonable to get a thumbnail sized image.

Jeremy Edwards
  • 14,620
  • 17
  • 74
  • 99
  • Apparently the core issue is that I'm getting back com.android.gallery3d.provider, and it should be com.google.android.gallery3d.provider. For some reason this appears to be broken on the motorola xoom. – Mark Jan 27 '12 at 14:32