Problems with accessing camera with targetSdkVersion 25? - android

I have an app that uses camera it works fine when I compile it with targetSdkVersion 23, but when I try to use version 25 I get this error:
android.os.FileUriExposedException:
file:///storage/emulated/0/DCIM/IMG_1093948364.jpg exposed beyond app
through ClipData.Item.getUri()
This is the code that I'm using:
private void showCameraAction() {
if(ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED){
requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
getString(R.string.mis_permission_rationale_write_storage),
REQUEST_STORAGE_WRITE_ACCESS_PERMISSION);
}else {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
try {
mTmpFile = FileUtils.createTmpFile(getActivity());
} catch (IOException e) {
e.printStackTrace();
}
if (mTmpFile != null && mTmpFile.exists()) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
startActivityForResult(intent, REQUEST_CAMERA);
} else {
Toast.makeText(getActivity(), R.string.mis_error_image_not_exist, Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getActivity(), R.string.mis_msg_no_camera, Toast.LENGTH_SHORT).show();
}
}
}
private void requestPermission(final String permission, String rationale, final int requestCode){
if(shouldShowRequestPermissionRationale(permission)){
new AlertDialog.Builder(getContext())
.setTitle(R.string.mis_permission_dialog_title)
.setMessage(rationale)
.setPositiveButton(R.string.mis_permission_dialog_ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(new String[]{permission}, requestCode);
}
})
.setNegativeButton(R.string.mis_permission_dialog_cancel, null)
.create().show();
}else{
requestPermissions(new String[]{permission}, requestCode);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if(requestCode == REQUEST_STORAGE_WRITE_ACCESS_PERMISSION){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
showCameraAction();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
What should I do? Thanks.

Your FileUtils.createTmpFile(getActivity()); probably uses file:// URI to share file with other app(in your case camera).
Android versions greater then 24 use content:// URIs instead, and will throw this exception when you try to share a file directly using the file:// URI.
A content URI allows you to grant read and write access using temporary access permissions
Take a look at FileProvider.

SOLUTION:
Changed this:
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
To this:
//getActivity() because its a fragment
Uri uri = FileProvider.getUriForFile(getActivity(),
getActivity().getPackageName()
, mTmpFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
And it worked.

Related

How to delete SDcard file in Android

I tried to delete the image file from the gallery, but it won't. Image files are output normally, and sharing functions are done. It can't write and delete in my App. Files are deleted from the default app.
I tried to delete it use File class and ContentResolver. but file has not been deleted.
Android targetSdkVersion is 26 and compileSdkVersion is 28.
Manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
I get SDcard path from getSDcardPath()
public String getSDcardPath(Context context) {
File[] storage = ContextCompat.getExternalFileDirs(context, null);
if(storage.length > 1 && storage[0] != null && storage[1] != null)
return storage[1].toString();
else
return "";
}
File Class code Used
public void useFileClass() {
File mFile = new File("file Parent + file NAME");
if (mFile.exists()) {
mFile.delete();
}
}
ContentResolver code Used
public void useContentResolver(Context context, File mFile) {
ContentResolver contentResolver = context.getContentResolver();
Uri mUri = getUri(context, mFile);
contentResolver.delete(mUri, null, null);
}
public Uri getUri(Context context, File mFile) {
Uri mUri;
mUri = FileProvider.getUriForFile(context, "MyApplication", mFile);
return mUri;
}
share code
public void shareImage() {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, getUri(this, mFile));
startActivity(Intent.createChooser(shareIntent, "Share image too..."));
}
You need request Permission before access into storage. Try this:
private static final int MY_WRITE_STORAGE_PERMISSION_CODE = 200;
private void checkPermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_WRITE_STORAGE_PERMISSION_CODE);
} else {
// Todo (Add, Delete, Edit, ...)
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == MY_WRITE_STORAGE_PERMISSION_CODE)
{
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
// Todo (Add, Delete, Edit, ...)
} else {
// Permission Deny
}
}
}
Hope this help you.

How to create a pdf file on button click in android?

I have 8 edittext fields in my android app, I enter the data manually into the same and at the end of the field there is so called "Save" button
What I want is when I click on the save button, a pdf file should be generated with all the values that I have filled in the edittext. Any help is appreciated.. Thanks
You can use itext7 library to do just that. But do look at their licensing as they mention you may need to buy license as soon as you are using it for commercial purpose.
I actually used itext5 which seems deprecated now. But the code should not be much different.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mContentEditText.getText().toString().isEmpty()){
mContentEditText.setError("Body is empty");
mContentEditText.requestFocus();
return;
}
try {
createPdfWrapper();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
});
The createPdfWrapper() method definition is as follows:
private void createPdfWrapper() throws FileNotFoundException,DocumentException{
int hasWriteStoragePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasWriteStoragePermission != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
showMessageOKCancel("You need to allow access to Storage",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_ASK_PERMISSIONS);
}
}
});
return;
}
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_ASK_PERMISSIONS);
}
return;
}else {
createPdf();
}
As you can see you will also need WRITE_EXTERNAL_STORAGE permission which should be declared in AndroidManifest.xml .
The permission result can be handled in onRequestPermissionsResult as:
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_PERMISSIONS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
try {
createPdfWrapper();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
} else {
// Permission Denied
Toast.makeText(this, "WRITE_EXTERNAL Permission Denied", Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
The other functions used here have the following definitions:
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
}
private void createPdf() throws FileNotFoundException, DocumentException {
File docsFolder = new File(Environment.getExternalStorageDirectory() + "/Documents");
if (!docsFolder.exists()) {
docsFolder.mkdir();
Log.i(TAG, "Created a new directory for PDF");
}
pdfFile = new File(docsFolder.getAbsolutePath(),"HelloWorld.pdf");
OutputStream output = new FileOutputStream(pdfFile);
Document document = new Document();
PdfWriter.getInstance(document, output);
document.open();
document.add(new Paragraph(mContentEditText.getText().toString()));
document.close();
previewPdf();
}
private void previewPdf() {
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("application/pdf");
List list = packageManager.queryIntentActivities(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
//Uri uri = Uri.fromFile(pdfFile); //This did not work, SO created a GenericFileProvider, register in xml, created provider_paths.xml
Uri uri = FileProvider.getUriForFile(getApplicationContext(),
getApplicationContext().getPackageName()
+ ".my.package.name.provider", pdfFile);
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
}else{
Toast.makeText(this,"Download a PDF Viewer to see the generated PDF",Toast.LENGTH_SHORT).show();
}
}
The main thing to look for here is the createPdf() method This is where I have created a PDF file with text from my EditText.
If you wish to have a look at the full code that I did you can visit my github respository here.
Good Luck!!!

Why this code of capturing picture from a device don't run properly?

I was just trying to write a code to capture an image and save that image in default directory with a name test.jpg. My device do capture the image but it runs the else part of the test case and shows error capturing image.In xml file there is only a button and android:onClick is set to process
public class MainActivity extends Activity {
private File imagefile;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void process(View v)
{
Toast.makeText(this,"Inside the process",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imagefile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"test.jpg");
Uri temp = Uri.fromFile(imagefile);
intent.putExtra(MediaStore.EXTRA_OUTPUT,temp);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,1);
startActivityForResult(intent,0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==0)
{
switch (resultCode){
case Activity.RESULT_OK:
if(imagefile.exists())
{
Toast.makeText(this,"File was saved at "+imagefile.getAbsolutePath(),Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this,"Error captureing image",Toast.LENGTH_SHORT).show();
}
break;
case Activity.RESULT_CANCELED:
break;
}
}
}
}
1.Use checkSelfPermission
2.Use requestPermissions
3.Use onRequestPermissionsResult
If permission is granted , you can do something you want ,else you should do requestPermissions in your code .
If you request permissions,you can deal with result in onRequestPermissionsResult method .And if permissions granted , you can do something you want ,else deal with that permission Denied .
Try this .
public static final int MY_PERMISSIONS_REQUEST_CAMERA = 0;
// process in your code
public void process(View view) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA);
} else {
// permission_granted
callMethod();
}
}
/**
* do something you want
*/
public void callMethod() {
Toast.makeText(this, "Inside the process", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imagefile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test.jpg");
Uri temp = Uri.fromFile(imagefile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, temp);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent, 0);
}
/**
* onRequestPermissionsResult
*
* #param requestCode
* #param permissions
* #param grantResults
*/
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
callMethod();
} else {
// Permission Denied
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

android6.0 can't get gallery path , I have got uses-permission

I want to get photo from my photo gallery to crop it, but the path is null. Andorid5.0 can use this way, but Android 6.0 and Android 7.0 can't use this way. I have got this app permission.
public void initPop(View view) {
albums = (TextView)view.findViewById(R.id.albums);
cancel = (LinearLayout) view.findViewById(R.id.cancel);
albums.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
openAlbumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(openAlbumIntent, PHOTOZOOM);
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
popupWindow.dismiss();
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
Uri uri = null;
switch (requestCode) {
case PHOTOZOOM:
if (data == null) {
return;
}
uri = data.getData();
String[] proj = {
MediaStore.Images.Media.DATA
};
Cursor cursor = getContentResolver().query(uri, proj, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
Log.i("Ienning", "onActivityResult: the cursor is " + column_index);
path = cursor.getString(column_index);
}
Intent intent3 = new Intent(PersonCenter.this, ClipActivity.class);
intent3.putExtra("path", path);
Log.i("Ienning", "The Path is " + path);
startActivityForResult(intent3, IMAGE_COMPLETE);
break;
case IMAGE_COMPLETE:
final String temppath = data.getStringExtra("path");
editor.putString("temppath", temppath);
editor.commit();
head.setImageBitmap(getLoacalBitmap(temppath));
break;
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
And permission code:
public void getpermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE))
{
new AlertDialog.Builder(this)
.setMessage("get permission")
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(PersonCenter.this, new String[] {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS}, MY_PERMISSIONS_REQUEST_WRITE_STORAGE);
}
}).show();
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS}, MY_PERMISSIONS_REQUEST_WRITE_STORAGE);
}
}
else {
Log.i("Ienning", " this is ok manifest permission");
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MY_PERMISSIONS_REQUEST_WRITE_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("Ienning", "onRequestPermissionResult: the result permission is ok!");
} else {
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "permission denied!", Toast.LENGTH_SHORT).show();
}
}
return;
}
}
And loginfo is
10-28 19:39:44.424 25265-25265/com.example.ienning.ncuhome I/Ienning: onActivityResult: the cursor is 0
10-28 19:39:44.425 25265-25265/com.example.ienning.ncuhome I/Ienning: The Path is null
Andorid5.0 can use this way
You did not test it very well. Your approach will fail on all Android devices, at least some of the time. It will fail more frequently on Android 6.0+.
Your code makes two invalid assumptions:
You assume that the Uri that comes back from ACTION_GET_CONTENT has something to do with the MediaStore. This is incorrect. The Uri that comes back from ACTION_GET_CONTENT can be anything that the user-selected activity wants to return. All that is more-or-less guaranteed is that you can use ContentResolver and openInputStream() to read the content.
You assume that the MediaStore will always give you a DATA column that is usable. That is not a requirement, even if the MediaStore happens to know about the Uri (see the previous bullet).
If the scheme of the Uri that you get back from ACTION_GET_CONTENT is file, then getPath() will be a filesystem path. You may be able to use that path (otherwise, it is a bug in the third-party app that gave you that Uri).
More commonly, the scheme of the Uri will be content. In that case, you can use ContentResolver and openInputStream() to read in the content identified by that Uri, but there is no required filesystem path behind that Uri. That Uri can point to anything the other developer wants: BLOB columns in databases, files in locations that you cannot access, data that needs to be downloaded because it is not yet on the device, etc.

Issues with requesting permissions Marshmallow

I'm trying to make a basic camera application that can access the saved photo from the gallery (needed as part of another app but due to problems I've been having I am developing this in a blank project), and have been following mainly this tutorial https://guides.codepath.com/android/Accessing-the-Camera-and-Stored-Media
Having then realised that it would just crash because of how permissions work in Marshmallow, and needing backward compatibility, I've tried to follow tutorials on implementing permission requests so that I can actually use the app.
This is what I currently have after several hours of trying. I have added permissions in the manifest, but as these are fairly standard I have not bothered to copy and paste these over. This currently crashes on the test() method because of there not being a group called Storage. With that line commented out, it will just say permission denied without prompting me to sort permissions (whether on a Marshmallow device or not). Frankly I am now at a loss. What I need this to do is before launching the camera in the onLaunchCamera method (which is launched off a button click), to get the permissions for reading and writing external storage and for accessing the camera. Any help you are able to give would be much appreciated.
private boolean cameraPermissionsCheck() {
return ContextCompat.checkSelfPermission(this, Manifest.permission_group.CAMERA) == PackageManager.PERMISSION_GRANTED;
}
private boolean storagePermissionsCheck() {
return ContextCompat.checkSelfPermission(this, Manifest.permission_group.STORAGE) == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission_group.CAMERA, Manifest.permission_group.STORAGE}, 123);
}
private void test() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission_group.STORAGE)) {
//was a toast notification here
requestPermissions();
} else {
requestPermissions();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 123
&& grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
}
public void onLaunchCamera(View view) {
//btn = (Button) findViewById(R.id.button);
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
if(!cameraPermissionsCheck() || !storagePermissionsCheck()){
test();
}
else {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri(photoFileName)); // set the image file name
if (intent.resolveActivity(getPackageManager()) != null) {
// Start the image capture intent to take photo
startActivityForResult(intent, 0);
}
}
} else {
Toast.makeText(MainActivity.this, "No Camera",
Toast.LENGTH_LONG).show();
}
}
Try this
public void onLaunchCamera(View view) {
//btn = (Button) findViewById(R.id.button);
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
checkPermission();
}
else {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri(photoFileName)); // set the image file name
if (intent.resolveActivity(getPackageManager()) != null) {
// Start the image capture intent to take photo
startActivityForResult(intent, 0);
}
}
} else {
Toast.makeText(MainActivity.this, "No Camera",
Toast.LENGTH_LONG).show();
}
}
private void checkPermission() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {//Can add more as per requirement
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA},
123);
} else {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,getPhotoFileUri(photoFileName)); // set the image file name
if (intent.resolveActivity(getPackageManager()) != null) {
// Start the image capture intent to take photo
startActivityForResult(intent, 0);
}
}
And make sure you have set proper version in your build.gradle
**compileSdkVersion 23
buildToolsVersion "23.0.2"**
defaultConfig {
applicationId "your_package_name"
minSdkVersion 15
**targetSdkVersion 23**
versionCode 1
versionName "1.0"
multiDexEnabled true
}

Categories

Resources