Reputation: 1085
I am working on the project of capturing photos or picking images from gallery and show it in the recycler view, the app is working good in Android-lollipop but crashes in marshmallow one as soon as camera button is clicked giving the exception
Caused by: java.lang.SecurityException: Permission Denial: writing com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=1983, uid=10060 requires android.permission.WRITE_EXTERNAL_STORAGE, or grantUriPermission()
Here is the code: Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.urjapawar.bevypart2">
<uses-permission tools:node="replace" android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission tools:node="replace" android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-feature
android:name="android.hardware.camera"
android:required="false"/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity><!-- ATTENTION: This was auto-generated to add Google Play services to your project for
App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information. -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
</manifest>
Images.java
public class Images {
String path;
public void setPath(String path) { this.path = path; }
public String getPath() {
return path;
}
/**
* Gets path.
*
* @return Value of path.
*/
@Override public String toString() {
return "\nPath:" + path;
}
}
MainActivity.java
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ArrayList<Images> images;
private ImageAdapter imageAdapter;
private RecyclerView rv;
private LinearLayoutManager llm;
private Uri mCapturedImageURI;
private static final int RESULT_LOAD_IMAGE = 1;
private static final int REQUEST_IMAGE_CAPTURE = 2;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
images = new ArrayList<>();
imageAdapter = new ImageAdapter(images);
rv = (RecyclerView) findViewById(R.id.rv);
llm = new LinearLayoutManager(this);
rv.setLayoutManager(llm);
imageAdapter = new ImageAdapter(images);
rv.setAdapter(imageAdapter);
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
public void activeCamera(View view) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
String fileName = "temp.jpg";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, fileName);
mCapturedImageURI = getContentResolver()
.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values);
takePictureIntent
.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
public void activeGallery(View view) {
Intent intent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RESULT_LOAD_IMAGE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RESULT_LOAD_IMAGE:
Uri selectedImage = null;
if (requestCode == RESULT_LOAD_IMAGE &&
resultCode == RESULT_OK && null != data) {
if (Build.VERSION.SDK_INT < 19) {
selectedImage = data.getData();
} else {
selectedImage = data.getData();
}
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver()
.query(selectedImage, filePathColumn, null, null,
null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
}
// cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
Images image = new Images();
image.setPath(picturePath);
images.add(image);
}
case REQUEST_IMAGE_CAPTURE:
if (requestCode == REQUEST_IMAGE_CAPTURE &&
resultCode == RESULT_OK) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor =
getContentResolver().query(mCapturedImageURI, projection, null,
null, null);
int column_index_data = cursor.getColumnIndexOrThrow(
MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String picturePath = cursor.getString(column_index_data);
Images image = new Images();
image.setPath(picturePath);
images.add(image);
cursor.close();
}
}
}
}
ImageAdapter.java
import android.graphics.BitmapFactory;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.support.v7.widget.*;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.util.List;
public class ImageAdapter extends android.support.v7.widget.RecyclerView.Adapter<ImageAdapter.ImgViewHolder> {
List<Images> images;
ImageAdapter(List<Images> img){
this.images = img;
}
public class ImgViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder
{
ImageView personPhoto;
CardView cv;
public ImgViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.card_view);
personPhoto=(ImageView)itemView.findViewById(R.id.thumbnail);
}
}
@Override
public ImgViewHolder onCreateViewHolder(final ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_card, viewGroup, false);
ImgViewHolder pvh = new ImgViewHolder(v);
return pvh;
}
@Override
public int getItemCount() {
return images.size();
}
@Override
public void onBindViewHolder(ImgViewHolder holder, int i) {
Images image = images.get(i);
final int THUMBSIZE = 96;
// viewHolder.imgIcon.setImageURI(Uri.fromFile(new File(image
// .getPath())));
holder.personPhoto.setImageBitmap(ThumbnailUtils
.extractThumbnail(BitmapFactory.decodeFile(image.getPath()),
THUMBSIZE, THUMBSIZE));
// holder.personPhoto.setImageURI(Uri.parse("file://" + images.getPath() + "/" + mDataset[position]));
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
}
I have checked many answers but not able to fix it, kindly help! Also while selecting images from gallery blank card shows up in marshmallow (no image content), it says Make sure the Cursor is initialized correctly before accessing data from it. while it works fine in lollipop one. Any suggestions will be deeply appreciated.
Upvotes: 0
Views: 8496
Reputation: 258
You must put Camera permission in code since android 6 + version checks for runtime permission.
public void getCameraPermission(){
if (!checkPermission()) {
requestPermission();
}
}
private boolean checkPermission(){
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);
if (result == PackageManager.PERMISSION_GRANTED){
return true;
} else {
return false;
}
}
private void requestPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)){
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE);
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this,"Permission granted",Toast.LENGTH_SHORT).show();
//store permission in shared pref
}
else {
Toast.makeText(MainActivity.this,"Permission denied",Toast.LENGTH_SHORT).show();
//store permission in shared pref
}
break;
}
}
Upvotes: 2
Reputation: 23
Just a thought, have you allowed your app to access your phone or SD card in the Manifest?
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Upvotes: -1
Reputation: 4328
You need to give android.hardware.Camera permission programmatically.
manifeast permission not work on Android Marshmallow
In marshmallow,We require runtime permissions for Storage,Contacts,Camera, etc. In edition to give these permissions in manifest for older version, We need to request them from users at Runtime for marshmallow. For more details refer this : Marshmallow permissions
Upvotes: 3
Reputation: 13785
You need to add
<uses-permission android:name="android.permission.CAMERA" />
Upvotes: 0