Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing images that are stored on internal memory

I have an application in which an ImageView is set and can be clicked to be opened in the gallery.

By default, I use the following code to get a file directory from the external storage to store my jpegs:

File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp");

But! Suppose the external storage is not mounted or simply does not exist (Galaxy Nexus), this doesn't work. So I wrote an if-statement around it and get the internal cache dir as a fall back.

String state = Environment.getExternalStorageState()
if(Environment.MEDIA_MOUNTED.equals(state)){ 
    File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp");    
}else{
    context.getCacheDir();
}

The images show up fine in the ImageView, but don't come through when my intent launches.

Intent intent = new Intent();             
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(imgFile), "image/jpeg");
startActivity(intent);

The gallery gets loaded, but shows a black screen. Presumably because the gallery has no access to files in the cache dir of my app.

As an alternative, I tried using the media content provider that uses MediaStore.Images.Media.INTERNAL_CONTENT_URI, but this leads to an error when trying to inser the image:

java.lang.UnsupportedOperationException: Writing to internal storage is not supported.

What should I do?

like image 311
Maarten Avatar asked Dec 13 '12 21:12

Maarten


People also ask

What is shared internal storage?

Shared storage: Store files that your app intends to share with other apps, including media, documents, and other files. Preferences: Store private, primitive data in key-value pairs. Databases: Store structured data in a private database using the Room persistence library.

How are data stored in the internal memory?

Primary storage (also known as main memory, internal memory, or prime memory), often referred to simply as memory, is the only one directly accessible to the CPU. The CPU continuously reads instructions stored there and executes them as required. Any data actively operated on is also stored there in uniform manner.

What is stored in internal storage?

Android Internal storage is the storage of the private data on the device memory. By default, saving and loading files to the internal storage are private to the application and other applications will not have access to these files.


1 Answers

i suppose the problem here is that you are trying open with the gallery a file saved in a private space of memory (getCacheDir return a path relative to your application and only your application can access that memory path)

If you can't save in external memory, you can try to save in a public path (but that way your media files can be manipulated by every app and if you uninstall your application it doesn't clean generated media that you saved there)

If you want to use private internal memory, you can write your ContentProvider

i edit to post a content provider i use to acomplish what i said. this is my content provider (i just posted the relevant part you need):

public class MediaContentProvider extends ContentProvider {
private static final String TAG = "MediaContentProvider";

// name for the provider class
public static final String AUTHORITY = "com.way.srl.HandyWay.contentproviders.media";

private MediaData _mediaData;

// UriMatcher used to match against incoming requests
private UriMatcher _uriMatcher;

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public String getType(Uri uri) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public boolean onCreate() {
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    // Add a URI to the matcher which will match against the form
    // 'content://com.stephendnicholas.gmailattach.provider/*'
    // and return 1 in the case that the incoming Uri matches this pattern
    _uriMatcher.addURI(AUTHORITY, "*", 1);

    return true;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {

    Log.v(TAG, "Called with uri: '" + uri + "'." + uri.getLastPathSegment());

    // Check incoming Uri against the matcher
    switch (_uriMatcher.match(uri)) {

    // If it returns 1 - then it matches the Uri defined in onCreate
        case 1:

            // The desired file name is specified by the last segment of the
            // path
            // E.g.
            // 'content://com.stephendnicholas.gmailattach.provider/Test.txt'
            // Take this and build the path to the file
            // String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment();
            Integer mediaID = Integer.valueOf(uri.getLastPathSegment());

            if (_mediaData == null) {
                _mediaData = new MediaData();
            }
            Media m = _mediaData.get(mediaID);

            // Create & return a ParcelFileDescriptor pointing to the file
            // Note: I don't care what mode they ask for - they're only getting
            // read only
            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(m.filePath), ParcelFileDescriptor.MODE_READ_ONLY);
            return pfd;

            // Otherwise unrecognised Uri
        default:
            Log.v(TAG, "Unsupported uri: '" + uri + "'.");
            throw new FileNotFoundException("Unsupported uri: " + uri.toString());
    }
}

then you need in the manifest the reference to your contentprovider, in my case it was

<provider
        android:name=".contentproviders.MediaContentProvider"
        android:authorities="com.way.srl.HandyWay.contentproviders.media" >
    </provider>

and then use it like this

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("content://" + MediaContentProvider.AUTHORITY + "/" + m.id), "image/jpg");

in my case m is an entity that store an id that point to a sqlite db and i use a class that fetch data to populate again the object (with _mediaData), you can just change the code to fit your needs

this way i solved exactly your problem in my application

like image 196
Not Important Avatar answered Oct 12 '22 13:10

Not Important