1

I have tried everything I could find by researching. Nothing is working. I have an Activity with a FragmentDialog. In this dialog, I have an image view with a button. When this button is pressed, an alert pops up to take pic, choose pic from gallery or cancel. Both the cancel and the gallery buttons work great, but when I try to take a photo, I get the error message in the title:

FATAL EXCEPTION: java.lang.SecurityException: Permission Denial: starting Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.lge.camera/.app.CameraActivity } from ProcessRecord{c6d8bdf 7649:com.devhopes.ryde/u0a152} (pid=7649, uid=10152) with revoked permission android.permission.CAMERA

Below is my DialogFragment and Manifest Code:

UsernameDialogFragment

   public static class UsernameDialogFragment extends DialogFragment {

    Context applicationContext = bDriverRegistrationActivity.getContextOfApplication();

    private ImageView profilePic;
    private int REQUEST_CAMERA = 0, SELECT_FILE = 1;
    private Button btnSelect;
    private String userChosenTask;

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case Utility.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if(userChosenTask.equals("Take Photo"))
                        cameraIntent();
                    else if(userChosenTask.equals("Choose from Library"))
                        galleryIntent();
                } else {
                    //code for deny
                }
                break;
        }
    }


    private void galleryIntent() {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);//
        startActivityForResult(Intent.createChooser(intent, "Select File"),SELECT_FILE);
    }


    private void cameraIntent() {
        Intent intent = new Intent(ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, REQUEST_CAMERA);
    }


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

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == SELECT_FILE)
                onSelectFromGalleryResult(data);
            else if (requestCode == REQUEST_CAMERA)
                onCaptureImageResult(data);
        }
    }


    private void onCaptureImageResult(Intent data) {
        Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);

        File destination = new File(Environment.getExternalStorageDirectory(),
                System.currentTimeMillis() + ".jpg");

        FileOutputStream fo;
        try {
            destination.createNewFile();
            fo = new FileOutputStream(destination);
            fo.write(bytes.toByteArray());
            fo.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        profilePic.setImageBitmap(thumbnail);
    }


    @SuppressWarnings("deprecation")
    private void onSelectFromGalleryResult(Intent data) {

        Bitmap bm=null;
        if (data != null) {
            try {
                bm = MediaStore.Images.Media.getBitmap(contextOfApplication
                        .getContentResolver(), data.getData());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        profilePic.setImageBitmap(bm);
    }


    private void selectImage() {
        final CharSequence[] items = { "Take Photo", "Choose from Library",
                "Cancel" };

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Add Photo!");
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                boolean result=Utility.checkPermission(getActivity());

                if (items[item].equals("Take Photo")) {
                    userChosenTask ="Take Photo";
                    if(result) {
                        cameraIntent();
                    }

                } else if (items[item].equals("Choose from Library")) {
                    userChosenTask ="Choose from Library";
                    if(result) {
                        galleryIntent();
                    }

                } else if (items[item].equals("Cancel")) {
                    dialog.dismiss();
                }
            }
        });
        builder.show();
    }


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        super.onCreateDialog(savedInstanceState);

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // Get the layout inflater
        LayoutInflater inflater = getActivity().getLayoutInflater();

        View dialogView = inflater.inflate(R.layout.username_dialog, null);

        // Select button
        btnSelect = (dialogView).findViewById(R.id.btnSelectPhoto);
        btnSelect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectImage();
            }
        });

        // profile pic
        profilePic = dialogView.findViewById(R.id.profile_pic);

        // Inflate and set the layout for the dialog
        // Pass null as the parent view because its going in the dialog layout
        builder.setView(dialogView);

       // ... Add action buttons ...

        builder.setPositiveButton(R.string.action_register, new DialogInterface.OnClickListener() {
            @Override
            public final void onClick(final DialogInterface dialog, int id) {
                // save the username to Firebase and sign in user  ...

                // ... casting dialog interface to an alert dialog and casting
                // the result of the findView to an EditText
                EditText usernameField  = (EditText)((AlertDialog) dialog).findViewById(username);
                String username = usernameField.getText().toString();

                // year
                EditText yearField = (EditText)((AlertDialog) dialog).findViewById(R.id.year);
                String year = yearField.getText().toString();

                // color, make and model
                EditText cmmField = (EditText)((AlertDialog) dialog).findViewById(R.id.cmm);
                String cmm = cmmField.getText().toString();

                // cell
                EditText cellField = (EditText)((AlertDialog) dialog).findViewById(R.id.cell);
                String cell = cellField.getText().toString();

                // license plate no.
                EditText plateField = (EditText)((AlertDialog) dialog).findViewById(R.id.licenseNo);
                String licenseNo = plateField.getText().toString();

                // profic pic
                ImageView profil_pic = (ImageView)((AlertDialog) dialog).findViewById(R.id.profile_pic);
                // TODO:  set up profile pic to save to firebase

                // ... get user's unique id
                String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();

                User aUser = new User(username, year, cmm, cell, licenseNo);


                /*  https://android-chat-af94c.firebaseio.com/android-chat-af94c/
                    users/pRsxsToJZPTzCdtft69f1grIJC13/profile/username

                    getInstance -> grabbing the url:
                    https://android-chat-af94c.firebaseio.com/android-chat-af94c/
                */
                // above is the same as below ...
                FirebaseDatabase.getInstance().getReference("drivers").child(userId).setValue(aUser);

                Intent intent = new Intent(getActivity().getBaseContext(), PoliciesActivity.class);
                startActivity(intent);
            }

        });

        return builder.create();

    }

}  // UsernameDialogFragment

AndroidManifest permissions

    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

<uses-permission android:name="android.permission.INTERNET"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.CAMERA"
    android:requiredFeature="true"/>
<uses-permission android:name="android.permission.STORAGE"/>

<!--
     The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
     Google Maps Android API v2, but you must specify either coarse or fine
     location permissions for the 'MyLocation' functionality. 
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

In the Android Monitor, it seems to point at 3 lines in particular:

  • startActivityForResult(intent, REQUEST_CAMERA);
  • public static class UsernameDialogFragment extends DialogFragment {
  • cameraIntent();
halfer
  • 19,824
  • 17
  • 99
  • 186
LizG
  • 2,246
  • 1
  • 23
  • 38
  • You have not requested the runtime permission for `CAMERA`, apparently. Also, FWIW, there is no `android:requiredFeature` attribute for ``. – CommonsWare Jul 21 '17 at 22:26
  • How do I request the runtime permission for CAMERA? – LizG Jul 21 '17 at 22:29
  • Call `requestPermissions()`. You have an `onRequestPermissionsResult()` method that seems to be unused, as you are not calling `requestPermissions()`. – CommonsWare Jul 21 '17 at 22:45
  • where do I call requestPermissions()? I don't have a method called requestPermissions() ... – LizG Jul 21 '17 at 22:56
  • Runtime permissions is covered in [the documentation](https://developer.android.com/training/permissions/requesting.html). – CommonsWare Jul 21 '17 at 23:08

3 Answers3

1

If you are testing your app with Android 6.x or 7.x version you need to grant some permission (Location,camera etc..) at run time.You can find how to achieve this in here. https://developer.android.com/training/permissions/requesting.html

FnR
  • 75
  • 1
  • 5
1

If you are targeting API Level 23 or more, then you should force get permissions like below(contains several permissions, you can add or remove based on your requirement). Put this in a separate class:

public static List<String> checkAndRequestPermissions(Context context) {

    int camera = ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA);
    int readStorage = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE);
    int writeStorage = ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
    int fineLoc = ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION);
    int coarseLoc = ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION);
    List<String> listPermissionsNeeded = new ArrayList<>();

    if (camera != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(android.Manifest.permission.CAMERA);
    }
    if (readStorage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(android.Manifest.permission.READ_EXTERNAL_STORAGE);
    }
    if (writeStorage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    if (fineLoc != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(android.Manifest.permission.ACCESS_FINE_LOCATION);
    }
    if (coarseLoc != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(android.Manifest.permission.ACCESS_COARSE_LOCATION);
    }

    return listPermissionsNeeded;
}

And in your activity:

public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;  // Declare this integer globally

Add this method(to retrieve permissions):

private boolean permissions(List<String> listPermissionsNeeded) {

    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray
                (new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
        return false;
    }
    return true;
}

And force get permissions like this:

// In my case I've put the 'checkAndRequestPermissions' method in a separate class named 'PermissionUtils'
List<String> permissionList = PermissionUtils.checkAndRequestPermissions(this);  

     if (permissions(permissionList)) {

          dispatchTakePictureIntent();  // call your camera instead of this method
     }
vss
  • 1,093
  • 1
  • 20
  • 33
0

Request the permissions you need at runtime. Code is from here so check it out

if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.READ_CONTACTS)
    != PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
        Manifest.permission.READ_CONTACTS)) {

    // Show an explanation to the user *asynchronously* -- don't block
    // this thread waiting for the user's response! After the user
    // sees the explanation, try again to request the permission.

} else {

    // No explanation needed, we can request the permission.

    ActivityCompat.requestPermissions(thisActivity,
            new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant. The callback method gets the
    // result of the request.
}
}
nKalai
  • 132
  • 1
  • 2
  • 5