Urja Pawar Urja Pawar - 2 months ago 18
Android Question

App crashes due to java.lang.SecurityException

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.

Answer

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;
    }
}