How to Save Image File in Android Oreo Update. How to Do It

Unable to save image file in android oreo update. How to do it?

There is, in fact, a slight, subtle change in Permissions for apps running on and targeting API 26.

Previously, apps were automatically granted all permissions in a given group if at least one permission in that group had been granted by the user. This means that an app that had been granted the READ_EXTERNAL_STORAGE would've had WRITE_EXTERNAL_STORAGE immediately granted to it as well, regardless of whether WRITE_EXTERNAL_STORAGE had been explicitly requested.

As of Oreo, for apps targeting API 26+, this has been corrected, and only those permissions that are explicitly requested will be granted. If the user has already granted a permission in the same group, then there will be no prompt for the new permission, but it still must be requested.

That was the problem, in this case. When the READ_EXTERNAL_STORAGE permission was granted to your app on Nougat or below, you were automatically getting WRITE_EXTERNAL_STORAGE, too, without having to request that one specifically. When you try the same file save procedure in Oreo, you aren't getting WRITE_EXTERNAL_STORAGE automatically, so the write ultimately fails.

Simply add a specific request for WRITE_EXTERNAL_STORAGE. If the user has already granted READ_EXTERNAL_STORAGE, they won't be bothered with another prompt. Alternatively, you could request solely WRITE_EXTERNAL_STORAGE from the start, which implicitly includes READ_EXTERNAL_STORAGE, and would save you the need for two separate requests.

File read and write in Android 8.1 and above

For 8.0 and above only those permissions that are explicitly requested will be granted.

Did you add Read and Write request permission explicitly at runtime?

Unable to save image file in android oreo update. How to do it?

URI Location to save a photo

I created PictureUtils class for capture image from camera and Gallery. Here is below code

PictureUtils.java

public class PictureUtils {

private static String fileName;
public Activity activity;

public PictureUtils(Activity activity){
this.activity = activity;
}

public Uri openCameraIntent(int requestCode) {
Uri file = null;
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
file = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", getOutputMediaFile());
} else {
file = Uri.fromFile(getOutputMediaFile());
}

intent.putExtra(MediaStore.EXTRA_OUTPUT, file);
activity.startActivityForResult(intent, requestCode);

return file;
}

public void openGalleryIntent(int requestCode) {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickPhoto.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivityForResult(pickPhoto, requestCode);
}

private static File getOutputMediaFile() {

File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/RVRB");

if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
String timeStamp = String.valueOf(System.currentTimeMillis());
fileName = timeStamp + ".jpg";

return new File(mediaStorageDir.getAbsolutePath() + File.separator + fileName);
}

public ImagesData resultFromCamera(Intent data) {

File imageFile = null;
float rotationDegree = 0;
String exifOrientation;
ExifInterface exif = null;

Bitmap rotatedBitmap = null;

File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/RVRB");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
imageFile = new File(storageDir, fileName);
}

try {
exif = new ExifInterface(imageFile.getAbsolutePath());
exifOrientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);

if (Integer.parseInt(exifOrientation) >= 0 && Integer.parseInt(exifOrientation) <= 1) {
rotationDegree = 0;
} else if (Integer.parseInt(exifOrientation) >= 2 && Integer.parseInt(exifOrientation) <= 4) {
rotationDegree = 180;
} else if (Integer.parseInt(exifOrientation) >= 7 && Integer.parseInt(exifOrientation) >= 8) {
rotationDegree = 270;
} else {
rotationDegree = 90;
}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Bitmap thumbnail = null;
if (data != null && data.getData() != null) {
try {
thumbnail = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), data.getData());
Matrix matrix = new Matrix();
matrix.postRotate(rotationDegree);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(thumbnail, thumbnail.getWidth(), thumbnail.getHeight(), true);
rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);

if (imageFile != null) {
OutputStream fOut = new FileOutputStream(imageFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, fOut);
fOut.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {

thumbnail = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), Uri.fromFile(imageFile));

Matrix matrix = new Matrix();
matrix.postRotate(rotationDegree);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(thumbnail, thumbnail.getWidth(), thumbnail.getHeight(), true);
rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);

if (imageFile != null) {
OutputStream fOut = new FileOutputStream(imageFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, fOut);
fOut.close();
}

} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
try {
Bitmap bitmap = null;
imageFile = new File(storageDir, fileName);

bitmap = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), Uri.fromFile(imageFile));

if (bitmap != null && (bitmap.getHeight() < bitmap.getWidth())) {
Matrix matrix = new Matrix();
matrix.postRotate(rotationDegree);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), true);
rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);

if (imageFile != null) {
OutputStream fOut = new FileOutputStream(imageFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, fOut);
fOut.close();
}
} else {
rotatedBitmap = bitmap;
}

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

return new ImagesData(imageFile, rotatedBitmap);
}

public ImagesData imageFromGallery(Intent data) {

File imageFile = null;
float rotationDegree = 0;
Bitmap rotatedBitmap = null;
try {
Bitmap bm = null;
Uri selectedImage = null;
if (data != null && data.getData() != null) {
try {
selectedImage = data.getData();
bm = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), selectedImage);

} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
bm = (Bitmap) data.getExtras().get("data");
} catch (Exception e) {
e.printStackTrace();
}
}

String timeStamp = String.valueOf(System.currentTimeMillis());
String fileName = timeStamp + ".jpg";

File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/RVRB");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
imageFile = new File(storageDir, fileName);
}

rotationDegree = getRotationFromURI(selectedImage, activity);

Matrix matrix = new Matrix();
matrix.postRotate(rotationDegree);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bm, bm.getWidth(), bm.getHeight(), true);
rotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);

if (imageFile != null) {
OutputStream fOut = new FileOutputStream(imageFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, fOut);
fOut.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return new ImagesData(imageFile, rotatedBitmap);
}

private int getRotationFromURI(Uri contentUri, Context mContext) {
Cursor cursor = null;
try {
String[] proj = new String[]{MediaStore.Images.ImageColumns.ORIENTATION};
cursor = mContext.getContentResolver().query(contentUri, proj, null, null, null);
assert cursor != null;
cursor.moveToFirst();
return cursor.getInt(0);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return 0;
}

public class ImagesData {

File imageFile = null;
Bitmap bitmap = null;

private ImagesData(File imageFile, Bitmap bitmap) {
this.imageFile = imageFile;
this.bitmap = bitmap;
}

public File getImageFile() {
return imageFile;
}

public void setImageFile(File imageFile) {
this.imageFile = imageFile;
}

public Bitmap getBitmap() {
return bitmap;
}

public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
}
}

Now you can call camera intent using below way on click of any button.

Global Declaration : Uri fileUri;

PictureUtils images = new PictureUtils(ArtistAddEditMembers.this);
fileUri = images.openCameraIntent(REQUEST_OPEN_CAMERA);

You can handel the result in onActivityResult method using below way.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == Activity.RESULT_OK) {
if (requestCode == REQUEST_OPEN_CAMERA) {
try {
PictureUtils images = new PictureUtils(ArtistAddEditMembers.this);
PictureUtils.ImagesData imagesData = images.resultFromCamera(data);

imageFile = imagesData.getImageFile();
finalBitmap = imagesData.getBitmap();

displayImagePreview(finalBitmap);

} catch (Exception e) {
e.printStackTrace();
}
} else if (requestCode == REQUEST_OPEN_GALLERY) {
try {

PictureUtils images = new PictureUtils(ArtistAddEditMembers.this);
PictureUtils.ImagesData imagesData = images.imageFromGallery(data);

imageFile = imagesData.getImageFile();
finalBitmap = imagesData.getBitmap();

displayImagePreview(finalBitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

For Display image in imageview

public void displayImagePreview(Bitmap bitmap) {
Glide.with(mContext).load(bitmap).into(ivUserProfile);
}

or you can simply set image bitmap in imageview without using glide.

I handeled below case in above example.

  • If version is >= N, the I am using FileProvider.getUriForFile and Uri.fromFile for lower version.
  • Display right rotation of Image instead of Display image after rotate.

Add below code in AndroidManefest.xml file under application tag for file provider

<application
......>

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>

Create filepaths.xml file under xml resource directory

<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>

Make sure you popup and handel runtime permission for Camera and Write Internal Storage permission before call camera intent.

Image Save to SdCard for 6.0.1 Android Version

On Android 6.0+, you need to request runtime permission to write to external storage.


In order to request runtime permission to write to external storage:

public class MarshmallowPermission {
public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 2;

public MarshmallowPermission() {
}

public boolean checkPermissionForExternalStorage(Activity activity) {
if(Build.VERSION.SDK_INT >= 23) {
int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
} else {
return true;
}
}

public void requestPermissionForExternalStorage(Activity activity) {
if(ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(activity,
"External Storage permission needed. Please allow in App Settings for additional functionality.",
Toast.LENGTH_LONG).show();
// user has previously denied runtime permission to external storage
} else {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
}
}
}

Then you can do

if(!marshmallowPermission.checkPermissionForExternalStorage(this)) {
marshmallowPermission.requestPermissionForExternalStorage(this);
} else {
// can write to external
}

And

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == MarshmallowPermission.EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE) {
if(marshmallowPermission.checkPermissionForExternalStorage(this)) {
// can write to external
} else {
// runtime permission denied, user must enable permission manually
}
}
}

Screenshot image file is not visible in the gallery in Oreo

The Solution is using MediaScannerConnection after saving your image to Memory.

        // Tell the media scanner about the new file so that it is
// immediately available to the user.

MediaScannerConnection.scanFile(this,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});

Check for referrence

Android Oreo (API 26) - Create dir in external storage

I have no problems running your existing code on a Nexus 5X running Android 8.0. Using adb shell ls /storage/emulated/0, I see Chores/, and inside there I see Processed Audio/. This is for an app with WRITE_EXTERNAL_STORAGE permission, including runtime permissions.

That being said, ideally, do not use string concatenation to create File objects. Instead, use:

final File dir = new File(new File(Environment.getExternalStorageDirectory(), "Chords"), "Processed Audio");

Saving file shows Permission Denied though permission granted

You can try the following:

AsyncTask fileTask = new AsyncTask() {
@Override
protected Object doInBackground(Object[] objects) {
File directory = new File(Environment.getExternalStorageDirectory() + File.separator + "MyApplication");
if (!directory.exists()) {
directory.mkdirs();
}
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String name = " "+n+".jpg";
File pictureFile = new File(directory, name);
pictureFile.createNewFile();
try {
FileOutputStream out = new FileOutputStream(pictureFile);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
};
fileTask.execute();

Refer this for help

android studio - manually download system image for emulator

In windows: First locate your android-sdk. By default it's in your C:\Users\Your.name\AppData\Local\
in it's root folder. where you can find: SDK Manager.exe, make a folder name it "system-images", my api 25 image is at system-images\android-25\google_apis\x86_64\Files

Hope you can Figure it out. Comment if you have any problem.



Related Topics



Leave a reply



Submit