7

I've been using the way the system saves screenshots to save my bitmaps to the disk and gallery. This works in Android 4.2 and before but not in Android 4.3.

Relevant code :

Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
OutputStream out = resolver.openOutputStream(uri);

Full code here.

In 4.3 (new Nexus 7) however, I get a FileNotFoundException on the second line. I couldn't see any changes in 4.3 relevant to this on the website.

So what is the right way to save an image to the disk and gallery?

Verified :

  • storage is mounted with this method
  • imageUri is not null (usually something like "content://media/external/images/media/2034")
  • manifest has permission android.permission.WRITE_EXTERNAL_STORAGE
f2prateek
  • 2,034
  • 2
  • 20
  • 26
  • Are u using a HTC for testing? – Pulkit Sethi Jul 28 '13 at 23:26
  • Updated OP to clarify that this is on the emulator. However users have reported that the 4.3 update breaks the application and I'm confident it is due to this issue. – f2prateek Jul 28 '13 at 23:39
  • Does your emulator has mounted SD card, I mean, it happens one to forget enable SD emulation? :) Can you check if file exists if not, create tempfile and write that to the outputstream you get from the ContentResolver – Nikola Despotoski Jul 29 '13 at 02:32
  • Yes I have verified that storage is mounted with this method http://pastebin.com/EbUJHnKK – f2prateek Jul 29 '13 at 13:56
  • Does the FNF-exception message read **"App op not allowed"**? The only thing I see changing in 4.3 is the way they deal with file permissions. I'm not sure why it would affect you, but I don't see anything else. You can see the diff for the likely change here: https://github.com/android/platform_frameworks_base/commit/35654b61e8fe7bc85afcb076ddbb590d51c5865f – Geobits Jul 29 '13 at 14:26
  • Same problem. Tried on Nexus4 with 4.3 – Srikant Sahay Jul 29 '13 at 14:27
  • Does logcat tell you anything relevant? – Yusuf X Jul 31 '13 at 19:48
  • Pastebin for stacktrace is linked in OP http://pastebin.com/PrDFLnCZ – f2prateek Jul 31 '13 at 19:59
  • Did you manage to solve it? MediaStore.Images.Media.insertImage (ContentResolver cr, Bitmap source, String title, String description) is for storing a bitmap and the error is the same on Nexus 7. – Yar Jan 17 '14 at 15:32
  • For a temporary fix, I explicitly call folder.mkdirs() for the path I'm saving to. – f2prateek Jan 17 '14 at 18:08

4 Answers4

1

This is the way I save bitmaps to the Gallery:

Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri; //instantiate Uri with location of image
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
Phil
  • 35,852
  • 23
  • 123
  • 164
  • Is this actually relevant to storing a BITMAP in gallery? I mean MediaStore.Images.Media.insertImage (ContentResolver cr, Bitmap source, String title, String description) – Yar Jan 17 '14 at 15:32
  • @Yar, Yes - this does the exact same thing, just a different way - by broadcasting an intent that the given URI containing the image's location should be added to the gallery. – Phil Jan 17 '14 at 15:36
  • So if I have a raw Bitmap, should I store it somewhere on SD card and then broadcast the intent? Uri set to my new file? – Yar Jan 17 '14 at 15:42
  • @Yar yes, that is exactly what you should do. – Phil Jan 17 '14 at 19:37
0

In your manifest file try with change target sdk to 18.-

  <uses-sdk android:minSdkVersion="7" 
    android:targetSdkVersion="18"/>

It might solve your prob(May not). In 4.3 JELLY_BEAN_MR2, android did couple of changes and android clearly written that Your app might misbehave in a restricted profile environment. so please look at http://developer.android.com/about/versions/android-4.3.html

T_V
  • 17,440
  • 6
  • 36
  • 48
0

I have these permission in my Manifest.

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

But I am using a Target SDK version 15. Is there a requirement that you have to use a target SDK 18?

BTW:

Here is a sample code for downloading profile pictures from Facebook:

private class DownloadProfilePicTask extends AsyncTask<Void,String,String> {
    Bitmap profilePic;
    String fileName;
    String id;
    String type;
    URL img_value;
    public DownloadProfilePicTask(String i,String ty)
    {
        id = i;
        if(id==null)
        {
            //Log.v("Id is null", "Error");
        }
        //Log.v("Download Profile Pic Task initialized for id:",id);
        type = ty;
    }
    @Override
    protected String doInBackground(Void...param) {
         String root = Environment.getExternalStorageDirectory().toString();
         if(root==null)
         {
             return null;
         }
         try{
         profilePic = BitmapFactory.decodeStream(img_value.openConnection().getInputStream());
         }
         catch (IOException e) {
             e.printStackTrace();

         }

        if(profilePic == null)
        {
            //Log.v("profilePic is null", "Error");
        }
         //Log.v("Root for saving images",root );
         File myDir = new File(root + "/saved_images");
         myDir.mkdirs();
        fileName = root + "/saved_images/" + id + ".png";
        //Log.v("filename is ",fileName);
         File file = new File (fileName); 
         fileName = file.getPath();
         if (file.exists ()) file.delete (); 
         try {
                FileOutputStream out = new FileOutputStream(file);
                profilePic.compress(Bitmap.CompressFormat.PNG, 90, out);
                out.flush();
                out.close();
         } catch (Exception e) {
                e.printStackTrace();
         }
         return id;
    }
    @Override
    protected void onPreExecute()
    {
        try
        {
            img_value = new URL("http://graph.facebook.com/"+id+"/picture?type=" + type);
        }
         catch (MalformedURLException e) {
                e.printStackTrace();

        } 

    }
    @Override
    protected void onPostExecute(String result) {
    }
}

and then I just call:

new DownloadProfilePicTask(id,type).execute();

to download and automatically save images.

Note: You will have to play with filePath a bit for exact location.

Azhar Yousuf
  • 111
  • 6
0

There some changes in the fileSystem on Android 4.3 to start to avoid dev. to directly write in "/sdcard" or "/mnt/sdcard" but use the android ExternalStorage system. (http://source.android.com/devices/tech/storage/index.html)

N.B. : ExternalStorage can be an internal memory :p

For your case, have you tryed to use a method based on getExternalStorage ? (like this : Find an external SD card location)

Community
  • 1
  • 1
Goo
  • 1,318
  • 1
  • 13
  • 31