Android M Run time Permission issue - android

I have search a lot about this problem but i didn't find any solution why this happening?
Currently i have face strange problem with run time permission ,i'm trying to ask runtime permission for camera and it's work fine but my problem is when user allow the permission my code for pick video from gallery and make thumbnail with ThumbnailUtils but it will return null once when my app is install first time i mean when user first time allow for permission it will return null after all the cases thumbnailutil works fine,As well as below android M its work fine for first time too.
What I'm currently doing is
Ask for appropriate permission and after check allow or deny further i process for select video from gallery as per my requirement
-----------------Camera Permission-----------------
public void requestPermissionForCamera() {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)) {
Toast.makeText(activity, "Camera permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
}
}
-----------------External Storage permission--------------------
public void requestPermissionForExternalStorage() {
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();
} else {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
}
}
Below is my onRequestPermissionsResult & onActivityResult
UPDATE:
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_WRITE_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// my code for open video or image gallery
} else {
//SnackBar "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission"
}
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == FragmentActivity.RESULT_OK) {
if (requestCode == SELECT_VIDEO) {
Uri videoUri = data.getData();
selectedVideoPath = getRealPathFromURI(videoUri);
if (selectedVideoPath == null) {
Log.e("vediotag", "selected video path = null" + selectedVideoPath);
} else {
Log.e("vediotag", "selected video path----" + selectedVideoPath);
//create video thumbnail
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(selectedVideoPath, MediaStore.Video.Thumbnails.MINI_KIND);
insertData(mimageTitle, bitmap, selectedVideoPath);
}
}
}
}
public String getRealPathFromURI(final Uri contentURI) {
Cursor cursor = getActivity().getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
return contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
if (idx == -1) {
return contentURI.getPath();
}
String rvalue = cursor.getString(idx);
cursor.close();
return rvalue;
}
}
Problem Which i'm currently facing
Above my code is working fine after activity recreate once,but it fail for the first time when i have install app and allow for permission.
NOTE:
I don't want to recreate activity programmatically so don't suggest me for doing that.
Any help will be much appreciated
Regards.

Related

Unpredictable behavior while saving images into storage

TLDR: Why isn't my app asking for runtime permissions despite I have written code for it?
I am saving an image into the storage, on button click by doing something like this:
// Function triggered when save button is pressed
private void saveImage(){
// Asking Runtime permissions for API level 23 and higher
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
finallySave();
} else {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},STORAGE_WRITE_REQUEST_CODE);
}
} else {
// Do not ask permissions in the runtime for API level 22 and lower
finallySave();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_WRITE_REQUEST_CODE) {
if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
finallySave()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
private void finallySave(){
try {
File outFile = new File(imagesDir, "Abc " + System.currentTimeMillis() + ".png");
FileOutputStream outputStream = new FileOutputStream(outFile);
bitmaps[0].compress(Bitmap.CompressFormat.PNG, 100, outputStream);
outputStream.flush();
outputStream.close();
scanFile(outFile, "image/png");
} catch (Exception unused) {
}
}
The problem is, sometimes the image is not saved and the following error is shown:
java.io.FileNotFoundException: /storage/emulated/0/Abc/Abc 1601370822977.png (Permission denied)
I found out that this error is thrown when the application is not asking "storage write" permissions on the runtime. Which is the very origin of the problem that I am facing. My app is not asking for runtime permissions in some cases despite I have written the code for it. Replicating this bug is also very difficult because many times the saving operation is carried out successfully.
I am sure that my code for saving images works fine because sometimes it works (this happens when my app asks for runtime permissions) and sometimes it doesn't.
P.S: I encountered this problem when I had reinstalled my app (after uninstalling).
EDIT: imagesDir is a global variable I am assigning is as follows:
imagesDir = getImageDir(); // in onCreate
private File getImageDir() {
File directory = new File(
Environment.getExternalStorageDirectory() + "/Abc");
if (!directory.exists()) {
if (!directory.mkdirs()) {
Toast.makeText(this, "Could not create directory", Toast.LENGTH_SHORT).show();
return null;
}
}
scanFile(directory, "*/*");
return directory;
}

Android Camera photo cannot confirm creation

I want to open the camera, save the photo and pass it to an ImageView. However, I am able to take the photo but I cannot confirm the photo creation. I can also cancel or retake the photo but not confirm.
This is the related code that I used. It doesn't even get to onActivityResult when pressing the confirm button.
camera_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED){
requestPermissions(new String[]{ Manifest.permission.CAMERA }, CAMERA_CODE);
}else{
OpenCamera();
}
}
});
private void OpenCamera(){
File file = new File(DbHelper.ImageFolder.getPath() + File.separator + NewImageFileName());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", file);
image_path = uri.getPath();
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(intent, CAMERA_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length == 0 || grantResults[0] == PackageManager.PERMISSION_DENIED)
return;
switch (requestCode){
case CAMERA_CODE:
OpenCamera();
break;
case GALLERY_CODE:
OpenGallery();
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) return;
Bitmap image = null;
switch (requestCode){
case CAMERA_CODE:
image = BitmapFactory.decodeFile(image_path);
break;
case GALLERY_CODE:
try {
image = MediaStore.Images.Media.getBitmap(getContentResolver(), data.getData());
image_path = NewImageFileName();
// Then saves to local
} catch (IOException e) {
e.printStackTrace();
}
break;
default:
return;
}
food_image.setImageBitmap(image);
}
My cell phone is OnePlus 7 Pro. My code works on another phone I borrowed. I wonder if my code is wrong (or it needs some code to handle compatibility) or there is something wrong with the device. On the emulator (Pixel 3 XL), it keeps taking photos and there is no confirm.
My project is here.
Code posted is here.
---Update---
It seems there is something wrong with other settings. Now it keeps processing the image. And my emulator doesn't get the image set.
The main problem of mine is I forgot to check the permission of writing memory as saving the picture taken requires it:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }, WRITE_STORAGE);
Adding this properly would make my camera work.
My source code is here.
You are using "OnePlus 7 Pro" to run your app
and it's OS is Android 9.0 (Pie).
If you target to run your application that OS is upper then N you need some file sharing setting
1.Specify the FileProvider
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/filepaths" />
</provider>
...
</application>
</manifest>
2.Specify sharable directories in res/xml/filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>
Change some code in on onActivityResult
//*******
Bitmap image = null;
switch (requestCode){
case CAMERA_CODE:
Bundle extras = data.getExtras();
image = (Bitmap) extras.get("data");
break;
//*****
Android Developer Code Link for file sharing provider setting
Android Developer Code Link how to Take Photos

Runtime Permission Bug on Android API 28( i have to restart my app to display the captured image )

so i'm making an app that allows the user to take a photo and then display the taken picture on ImageView .
everything works great for me , i'm following the new rules for android 24+ to access the external storage .
(provider is included in Manifest & xml file path)
my problem is when i test it on Android API28
i can't display the picture if the permissions were just granted for First Time.
i have to restart the app for first time granting permissions to get the image path !
here's my example app :
TakePhoto Button :
private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
public void onTakePhotoClicked(View v){
if (!hasPermissions())
requestPermissions(permissions,CAPTURE_PERM_REQ_CODE);
else
invokeCamera();
}
handling requested permissions
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if(requestCode == CAPTURE_PERM_REQ_CODE && grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED && grantResults[2] == PackageManager.PERMISSION_GRANTED){
invokeCamera();
}
capture method
private void invokeCamera() {
// create the image Uri
Uri pictureUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1)
pictureUri = FileProvider.getUriForFile(getApplicationContext(),getPackageName() + ".provider",createImageFile());
else
pictureUri = Uri.fromFile(getImageFile());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// tell the camera where to save
intent.putExtra(MediaStore.EXTRA_OUTPUT,pictureUri);
// permission for saving the image
intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent,1144);
}
createImageFile method
private File getImageFile() {
File picturesDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
String imgName = "picture_JustForTest0X0X.jpg";
return new File(picturesDirectory.getPath(), imgName);
}
on Activity For Result
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAPTURE_REQ_CODE && resultCode == RESULT_OK){
Bitmap bitmap = BitmapFactory.decodeFile(getImageFile().getPath());
ImageView imageView = findViewById(R.id.imageView);
imageView.setImageBitmap(bitmap);
}
}
Please Go ahead and Try it out with Android API28 , you'll never get the image for first time permission granted. must restart the app this is strange.

Can't use Storage Access Framework in my app

I created an app a few years ago which had it's own file explorer and does so many processes on selected files. recently I wanted to add ability to write to external storages like SD Cards and Hard drives connected through OTG.
The problem is I can't rewrite the whole project based on DocumentFile structure since it's a very big project and it would take forever for me to update. So I needed to somehow convert the old File methods in a few lines and be done with it. this is what I've added so far :
private void getPersistentPermission() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
startActivityForResult(intent, reqcode_storage);
}
and :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == reqcode_storage) {
Uri uri = data.getData();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final int perm_flag = Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
grantUriPermission(getPackageName(), uri, perm_flag);
getContentResolver().takePersistableUriPermission(uri, perm_flag);
}
}
} else {
Log.d(tag, "something`s wrong !");
}
}
then I try to do something like this :
try {
DocumentFile dfile = DocumentFile.fromFile(file);
OutputStream os = getContentResolver().openOutputStream(dfile.getUri());
os.write(some_string.getBytes());
} catch (Exception e) {
Log.e(tag, e.toString());
} finally {
try {
os.close();
} catch (Exception ignored) {}
}
I get the "file" using implemented file explorer inside my app. it works for internal storage.
I read so many threads about SAF but somehow I can't get it to work. it always shows this error :
java.io.FileNotFoundException: Permission denied
Can anyone tell me what am I missing here ?
thanks in advance.

Not able to create the folder in external storage in marshmallow version

when I try to run this code in marshmallow the folder was not created..
the code is,I tried to run the same code its working fine except marshmallow
File folder = new File(Environment.getExternalStorageDirectory() + "/abcdefg");
boolean success = false;
if (!folder.exists()) {
success = folder.mkdir();
}
if (!success) {
Log.d("", "Folder not created.");
} else {
Log.d("", "Folder created!");
}
Try to add below code in your activity for requesting runtime permission.
Your need to require READ_EXTERNAL_STORAGE permission to create folder(directory) in external storage.
if (ActivityCompat.checkSelfPermission(YourActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_FOR_STORAGE);//REQUEST_FOR_STORAGE=1111
} else {
//Do your stuff here
}
...
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode == REQUEST_FOR_STORAGE){
//Do your stuff here
}
}
Hope its help you.
As marshmallow introduce Run time Permission you have to check for the permission
in run time. You can refer here
1.https://developer.android.com/training/permissions/requesting.html
2.https://www.youtube.com/watch?v=iZqDdvhTZj0
3.https://www.youtube.com/watch?v=C8lUdPVSzDk
You have to accept the STORAGE permission group from the user dynamically.
Go with the below link
http://developer.android.com/guide/topics/security/permissions.html

Categories

Resources