How to save file to public (external) storage on Android Q (API 29)?
Asked Answered
T

4

18

I have been using external storage in order to save a different type of files. That files needs to be visible to user. And now from Android Q, the method getExternalStoragePublicDirectory() has been deprecated getExternalStoragePublicDirectory(docs).

I used following code:

File externalFilesDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "DirectoryName");

Is there another way to save files which will be visible to user?

Triplett answered 13/8, 2019 at 10:19 Comment(2)
You need to use MediaStore to work with external storage from Android Q. This talk will give you some ideas of how to use it: youtube.com/watch?v=3EtBw5s9iRYAmu
You can also use getExternalFilesDir() on Context. See this blog post for more on the Q restrictions.Underpinnings
R
8

You need to add a check for Android Q. Let's assume you want to save the Image in your public Download folder.

try{
     OutputStream fos;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
       ContentResolver resolver = context.getContentResolver();
       ContentValues contentValues = new ContentValues();
       contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
       contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
       contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
       Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
       fos = resolver.openOutputStream(Objects.requireNonNull(imageUri));
    } else {
       String imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
       File image = new File(imagesDir, fileName);
       fos = new FileOutputStream(image);
    }
     finalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
     Objects.requireNonNull(fos).close();
}catch (IOException e) {
  // Log Message
}
Reddy answered 3/2, 2020 at 13:58 Comment(5)
There are out there a lot of examples with images since it's common format used for saving, but what I need is .pdf and .docx extensions of file. For that extensions I didn't found solution using MediaStore.Triplett
@Triplett was there any progress you were able to make on this?Ence
@Edwin Abraham I didn't work on that problem because everything still works on old fashion way.Triplett
It raises this exception: java.lang.IllegalArgumentException: Primary directory Download not allowed for content://media/external/images/media; allowed directories are [DCIM, Pictures]Diapositive
@EhsanHeidari You can change contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); to contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);External
P
2

Save capture Bitmap in android Q and below verison

private class AsyncTaskExample extends AsyncTask<String, String, Bitmap> {
        Bitmap icon = null;
        ByteArrayOutputStream bytes;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mBitmap = BaseApplication.getInstance().getBitmap();
        ((BaseActivity)mContext).showFullScreenProgressLoader(((BaseActivity)mContext), ((BaseActivity)mContext).getString(R.string.please_wait), ((BaseActivity)mContext).getString(R.string.we_are_processing_your_request));
    }

    @Override
    protected Bitmap doInBackground(String... strings) {
        try {



      String imageFileName = "picture_" + System.currentTimeMillis() + ".jpg";
                File directory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/" + Constants.INTERNAL_FOLDER_NAME + "/");
                directory.mkdirs();
                mFile = new File(directory, imageFileName);
                if (!mFile.isFile()) {
                    try {
                        mFile.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
                    final ContentResolver resolver = ((CameraFaceDetectionActivity) mContext).getContentResolver();
                    insertImage(resolver, mBitmap, mFile.getAbsolutePath(), "");
                } else {
                    FileOutputStream out = new FileOutputStream(mFile);
                    try {
//                    mBitmap = modifyOrientation(mBitmap,mFile.getAbsolutePath());
                        OutputStream output = new FileOutputStream(mFile);
                        mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);
                        output.flush(); // Not really required
                        output.close();
                    }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }




        } catch(Exception e){
            e.printStackTrace();
        }
        return mBitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    OutputStream output = new FileOutputStream(mFile);
                    Bitmap b = modifyOrientation(mBitmap, mFile.getAbsolutePath());
                    b.compress(Bitmap.CompressFormat.JPEG, 100, output);


                } catch (IOException e) {
                    e.printStackTrace();
                }

                startActivity(new Intent(mContext, SelfiePreviewForgetPsdActivity.class)
                        .putExtra(Constants.KEY_MOBILE, mMobileNumber)
                        .putExtra(Constants.KEY_COUNTRY_CODE, mCountryCode)
                        .putExtra(KEY_ID_NUMBER, idNumber)
                        .putExtra(Constants.KEY_USER_DETAIL, mVerifyUserDetailResponse)
                        .putExtra(KEY_ID_TYPE, idType)
                        .putExtra(Constants.IMAGE_PATH, mFile.getAbsolutePath()));
            }
        }, 500);
    }
}

below are the method for save bitmap on android Q for specify folder

public static String insertImage(ContentResolver cr,
                                 Bitmap source,
                                 String title,
                                 String description) {

    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, title);
    values.put(MediaStore.Images.Media.DISPLAY_NAME, title);
    values.put(MediaStore.Images.Media.DESCRIPTION, description);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
    // Add the date meta data to ensure the image is added at the front of the gallery
    values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
    values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());

    Uri url = null;
    String stringUrl = null;    /* value to be returned */

    try {
        url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        if (source != null) {
            OutputStream imageOut = cr.openOutputStream(url);
            try {
                source.compress(Bitmap.CompressFormat.JPEG, 100, imageOut);
            } finally {
                imageOut.close();
            }

            long id = ContentUris.parseId(url);
            // Wait until MINI_KIND thumbnail is generated.
            Bitmap miniThumb = MediaStore.Images.Thumbnails.getThumbnail(cr, id, MediaStore.Images.Thumbnails.MINI_KIND, null);
            // This is for backward compatibility.
            storeThumbnail(cr, miniThumb, id, source.getWidth(), source.getHeight(), MediaStore.Images.Thumbnails.MICRO_KIND);
        } else {
            cr.delete(url, null, null);
            url = null;
        }
    } catch (Exception e) {
        if (url != null) {
            cr.delete(url, null, null);
            url = null;
        }
    }

    if (url != null) {
        stringUrl = url.toString();
    }

    return stringUrl;
}

Save bitmap method

 private static final Bitmap storeThumbnail(
        ContentResolver cr,
        Bitmap source,
        long id,
        float width,
        float height,
        int kind) {

    // create the matrix to scale it
    Matrix matrix = new Matrix();

    float scaleX = width / source.getWidth();
    float scaleY = height / source.getHeight();

    matrix.setScale(scaleX, scaleY);

    Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
            source.getWidth(),
            source.getHeight(), matrix,
            true
    );

    ContentValues values = new ContentValues(4);
    values.put(MediaStore.Images.Thumbnails.KIND, kind);
    values.put(MediaStore.Images.Thumbnails.IMAGE_ID, (int) id);
    values.put(MediaStore.Images.Thumbnails.HEIGHT, thumb.getHeight());
    values.put(MediaStore.Images.Thumbnails.WIDTH, thumb.getWidth());

    Uri url = cr.insert(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, values);

    try {
        OutputStream thumbOut = cr.openOutputStream(url);
        thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
        thumbOut.close();
        return thumb;
    } catch (Exception ex) {
        return null;
    }
}
Praxis answered 20/3, 2020 at 13:29 Comment(2)
getExternalStoragePublicDirectory() has been deprecated in Android Q.Brandie
AsyncTask has been deprecated also.Denudation
H
0
File newDir = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "folder_name");
    if (!newDir.exists()) {
        newDir.mkdirs();
       }
    
File file = new File(newDir, imagename);
   try {
      FileOutputStream out = new FileOutputStream(file);
      bmpOverlay.compress(Bitmap.CompressFormat.PNG, 100, out);
      out.flush();
      out.close();
} catch (Exception e) {
     Log.e("interior", "Save image to SD");
}
Histoplasmosis answered 5/3, 2022 at 11:17 Comment(0)
I
-1
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)

replace to this:

   requireContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)!!.absolutePath
Influenza answered 16/1, 2020 at 12:14 Comment(2)
This path still going through my package nameFerguson
This is still internal not external.Principality

© 2022 - 2024 — McMap. All rights reserved.