Get a Content URI from a File URI?
Asked Answered
L

3

7

I am using the DownloadManager to download an image to the system's gallery and then in the Broadcast receiver (once the download succeeds) using an Intent to set the image as the wallpaper.

Everything was working fine but then recently on 4.4 I started to get an exception in the Photos/Google+ app because it is expecting a content URI and not a file URI.

So my question is if anyone knows how to convert a full file path/URI (file://) into a content style URI (content://)?

Sorry for the lack of source code, I am away from the computer that has the source, but I hope the question makes sense without it, get a content style uri from a full path.

EDIT:

The image is copied into the system's gallery or media gallery, not saved within my apps internal storeage.

Here is an example of what I want to convert:

file:///storage/emulated/0/Pictures/Rockstar/image.jpg

to

content://media/internal/images/media/445

EDIT 2:

Here is the error that I get from the Google+ app:

04-21 10:50:35.090: E/AndroidRuntime(7220): FATAL EXCEPTION: main
04-21 10:50:35.090: E/AndroidRuntime(7220): Process: com.google.android.apps.plus, PID: 7220
04-21 10:50:35.090: E/AndroidRuntime(7220): java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.plus/com.google.android.apps.photos.phone.SetWallpaperActivity}:  
java.lang.IllegalArgumentException: Image URI must be of the content scheme type

Here is the code that I use to let the user set the wallpaper:

String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
Uri u = Uri.parse(uriString);
Intent wall_intent =  new Intent(Intent.ACTION_ATTACH_DATA);
wall_intent.setDataAndType(u, "image/*");
wall_intent.putExtra("mimeType", "image/*");
Intent chooserIntent = Intent.createChooser(wall_intent,
    "Set As");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);      
try {
    context.startActivity(chooserIntent);
} 

Where uriString is:

file:///storage/emulated/0/Pictures/Rockstar/image.jpg
Lemniscate answered 21/4, 2014 at 23:15 Comment(0)
L
8

I was able to figure it out. It was a combination of the code found here: Converting android image URI and scanning the media file after downloading.

So after the file finished downloading I get the path and do the following:

String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));

//Update the System
Uri u = Uri.parse(uriString);                       
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, u));

//Get the abs path using a file, this is important          
File wallpaper_file = new File(u.getPath());
Uri contentURI = getImageContentUri(context, wallpaper_file.getAbsolutePath());

For some reason starting the media scanner, newing the file, and getting the absolute path are important, I'm not exactly sure why but I can't spend any more time on this!

The way to convert from a file URI to a content URI is as follows (taken from the linked StackOver flow post:

public static Uri getImageContentUri(Context context, String absPath) {
    Log.v(TAG, "getImageContentUri: " + absPath);

    Cursor cursor = context.getContentResolver().query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        , new String[] { MediaStore.Images.Media._ID }
        , MediaStore.Images.Media.DATA + "=? "
        , new String[] { absPath }, null);

    if (cursor != null && cursor.moveToFirst()) {
        int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
        return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI , Integer.toString(id));

    } else if (!absPath.isEmpty()) {
         ContentValues values = new ContentValues();
         values.put(MediaStore.Images.Media.DATA, absPath);
         return context.getContentResolver().insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    } else {
        return null;
    }
}

Maybe this will help someone in the future.

Lemniscate answered 22/4, 2014 at 15:16 Comment(1)
what is c here? I mean whats the defination of this cursor.Xerosere
M
1

So my question is if anyone knows how to convert a full file path/URI (file://) into a content style URI (content://)?

Implement a ContentProvider. FileProvider offers an out-of-the-box solution for serving up local files.

Morganmorgana answered 22/4, 2014 at 0:0 Comment(1)
I'm downloading the image (using the download manager) to the system's media gallery, and not storing the files in my app's internal storage. So would a ContentProvider be the way to go in that case? I have (for example) file:///sdcard/media/images/myimage.png and I want to convert to: content://media/internal/images/media/445Lemniscate
R
1

I'm not sure about the technique you are using to set the wallpaper but the easiest way is probably to use WallpaperManager.setStream() which doesn't require any URI.

Also note that a file URI only works between apps if the file is publicly accessible so a content URI is a more general solution.

Using a content URI implies that a ContentProvider will serve the file. Which one depends on where your file is located.

If your app has a direct read access to the file, you can implement a content provider in your app by using for example the FileProvider class of the support library, but this should really only be used if the file is located in the private data storage of your app.

If the image is added to the system media gallery, you should probably use the URI provided by the MediaStore.

Rightful answered 22/4, 2014 at 0:15 Comment(2)
Yes, the file is downloaded to the system's media gallery (using the download manger), but all that I have access to in the Broadcast receiver via the DownloadManager.COLUMN_LOCAL_URI column is the full path to the file. How can I get the URI from the MediaStore based on that full path? Also I'm using an intent and a URI so that the gallery or Photos app can crop the image.Lemniscate
I haven't tried myself, but take a look at the DownloadManager.COLUMN_MEDIAPROVIDER_URI column and check if it contains a content URI after the download is complete. If it seems too complicated, you can still implement your own content provider, but it feels like a hack to me.Rightful

© 2022 - 2024 — McMap. All rights reserved.