Android M Camera Intent + permission error?

I am trying to prepare my application for new rights changes on Android M and have discovered some strange behavior. My application uses the camera’s intent mechanism to allow the user to get an image from the camera. But in another action, you need to use the camera itself with a camera resolution (due to the fact that it requires a card-dependent library.)

However, with M in the activity, which is needed only for the camera, when I try to start the camera’s intent, I see the following failure (this does not happen if I remove the camera resolution from the manifest),

> 09-25 21:57:55.260 774-8053/? I/ActivityManager: START u0 > {act=android.media.action.IMAGE_CAPTURE flg=0x3000003 > pkg=com.google.android.GoogleCamera > cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity > (has clip) (has extras)} from uid 10098 on display 0 09-25 > 21:57:55.261 774-8053/? W/ActivityManager: Permission Denial: starting > Intent { act=android.media.action.IMAGE_CAPTURE flg=0x3000003 > pkg=com.google.android.GoogleCamera > cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity > (has clip) (has extras) } from null (pid=-1, uid=10098) with revoked > permission android.permission.CAMERA 09-25 21:57:55.263 32657-32657/? > E/ResolverActivity: Unable to launch as uid 10098 package > com.example.me.mycamerselectapp, while running in android:ui 09-25 > 21:57:55.263 32657-32657/? E/ResolverActivity: > java.lang.SecurityException: Permission Denial: starting Intent { > act=android.media.action.IMAGE_CAPTURE flg=0x3000003 > pkg=com.google.android.GoogleCamera > cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity > (has clip) (has extras) } from null (pid=-1, uid=10098) with revoked > permission android.permission.CAMERA 09-25 21:57:55.263 32657-32657/? > E/ResolverActivity: at > android.os.Parcel.readException(Parcel.java:1599) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Parcel.readException(Parcel.java:1552) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.app.ActivityManagerProxy.startActivityAsCaller(ActivityManagerNative.java:2730) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > android.app.Instrumentation.execStartActivityAsCaller(Instrumentation.java:1725) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > android.app.Activity.startActivityAsCaller(Activity.java:4047) 09-25 > 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity$DisplayResolveInfo.startAsCaller(ResolverActivity.java:983) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity.safelyStartActivity(ResolverActivity.java:772) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity.onTargetSelected(ResolverActivity.java:754) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ChooserActivity.onTargetSelected(ChooserActivity.java:305) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity.startSelected(ResolverActivity.java:603) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ChooserActivity.startSelected(ChooserActivity.java:310) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ChooserActivity$ChooserRowAdapter$2.onClick(ChooserActivity.java:990) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > android.view.View.performClick(View.java:5198) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.view.View$PerformClick.run(View.java:21147) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Handler.handleCallback(Handler.java:739) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Handler.dispatchMessage(Handler.java:95) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Looper.loop(Looper.java:148) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.app.ActivityThread.main(ActivityThread.java:5417) 09-25 > 21:57:55.263 32657-32657/? E/ResolverActivity: at > java.lang.reflect.Method.invoke(Native Method) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 09-25 > 21:57:55.286 1159-1159/? I/Keyboard.Facilitator: onFinishInput() 09-25 > 21:57:55.297 32657-32676/? E/Surface: getSlotFromBufferLocked: unknown > buffer: 0xaec352e0 09-25 21:57:55.344 325-349/? V/RenderScript: > 0xb3693000 Launching thread(s), CPUs 4 09-25 21:57:57.290 325-349/? > E/Surface: getSlotFromBufferLocked: unknown buffer: 0xb3f88240 

Is this a known issue with Android M? And more importantly, how do I get around this?

in the manifest, I have the following:

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

and this is the code that I use to let the user click the pic. using the camera and / or select an image

 public static Intent openImageIntent(Context context, Uri cameraOutputFile) { // Camera. final List<Intent> cameraIntents = new ArrayList<Intent>(); final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); final PackageManager packageManager = context.getPackageManager(); final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0); for(ResolveInfo res : listCam) { final String packageName = res.activityInfo.packageName; final Intent intent = new Intent(captureIntent); intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); intent.setPackage(packageName); intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraOutputFile); cameraIntents.add(intent); } // Filesystem. final Intent galleryIntent = new Intent(); galleryIntent.setType("image/*"); galleryIntent.setAction(Intent.ACTION_GET_CONTENT); // Chooser of filesystem options. final Intent chooserIntent = Intent.createChooser(galleryIntent, "Take or select pic"); // Add the camera options. chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{})); return chooserIntent; } 

I call openImageIntent() with a button click in my activity. When I do not have CAMERA permission in my application, it works fine, but with the addition I get the exception mentioned above.

  @Override public void onClick(View v) { Intent picCaptureIntenet = openImageIntent(MainActivity.this, getTempImageFileUri(MainActivity.this)); try { startActivityForResult(picCaptureIntenet, 100); } catch(Exception e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } 

+63
android android-6.0-marshmallow android-permissions android-camera android-camera-intent
Sep 25 '15 at 19:05
source share
9 answers

I had the same problem and I found this document from google: https://developer.android.com/reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE

"Note: If you use application M and above and declare using CAMERA permission, which is not granted, then attempting to use this action will throw a SecurityException."

This is really weird. You have no meaning. The application declares the resolution of the camera, using the intent with the IMAGE_CAPTURE action, it simply runs in a SecurityException. But if your application does not announce the resolution of the camera using the intent with the action, IMAGE_CAPTURE can launch the application for the camera without problems.

A workaround would be to verify that the application has a camera permission included in the manifest if it asks for camera permission before launching the intent.

Here's a way to check if permission is included in the manifest, it doesn't matter if permission is granted or not.

 public boolean hasPermissionInManifest(Context context, String permissionName) { final String packageName = context.getPackageName(); try { final PackageInfo packageInfo = context.getPackageManager() .getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); final String[] declaredPermisisons = packageInfo.requestedPermissions; if (declaredPermisisons != null && declaredPermisisons.length > 0) { for (String p : declaredPermisisons) { if (p.equals(permissionName)) { return true; } } } } catch (NameNotFoundException e) { } return false; } 
+79
Sep 30 '15 at 0:58
source share

If you are using the Android M permission model, first you need to check if the application has this permission at runtime and invite the user to this permission at runtime. The permission that you define in your manifest will not be automatically granted during installation.

 if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_REQUEST_CODE); } 

MY_REQUEST_CODE is a static constant that you can define that will be used again to call the requestPermission dialog.

You will need a callback for the result of the dialog:

 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Now user should be able to use camera } else { // Your app will not have this permission. Turn off all functions // that require this permission or it will force close like your // original question } } } 



change

Reading from a stack trace, it looks like the Google camera does not have CAMERA permission. In the end, it may look like backward compatibility.

Suppose a specific permission is required for a Google camera (or any other application that processes your ACTION intentions).

When your application does not have CAMERA permission, it simply allows Google Camera to do this with the old permission model.

However, with the CAMERA permission declared in your manifest, it also provides CAMERA permission on Google Camera (which doesn't have the Android M permission model) to use the Android M permission model (I think.)

Thus, this means using the method described above, you will need to provide permission for your application at runtime, which means that its child task (in this case, the Google camera) will also receive this permission.

+20
Sep 26 '15 at 11:55
source share

Regarding your question "Is this a known issue in M?" The Google developer replied that someone reported this issue as an error.

See here: https://code.google.com/p/android/issues/detail?id=188073&q=label%3APriority-Medium&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&start=100

Here is a word from a Google guy: “This is the intended behavior to avoid user frustration when they revoked the camera’s resolution from the application, and the application can still take pictures with the intention. Users don’t know that the photo after canceling the permission happens with another mechanism and will question the validity of the resolution model.This applies to MediaStore.ACTION_IMAGE_CAPTURE, MediaStore.ACTION_VIDEO_CAPTURE and Intent.ACTION_CALL documents for which the document changes behavior for applications oriented to and M. "

Since Google does not object to abstracting the mechanics of using the camera from your user, you can strategically initiate the first request for camera permission and refer to the Activity functionality that uses the camera as an argument for the request. If you allow your application to first make this permission request, when the user is simply trying to take a picture, the user might think that your application is behaving strangely, because getting a photo usually does not require permission.

+15
Oct 22 '15 at 21:17
source share

If you use Google M, go to Settings → Applications → your application → and specify the appropriate permissions.

+10
Nov 09 '15 at 3:37
source share

I am stuck with this problem and I have already used the JTY answer. The problem is that at some point the option "Never ask again" was checked in the query resolution dialog box. I am developing SDK 24.

My complete code for handling permissions (camera in my case):

 public void checksCameraPermission(View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Log.d("MyApp", "SDK >= 23"); if (this.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { Log.d("MyApp", "Request permission"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_REQUEST_CODE); if (! shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { showMessageOKCancel("You need to allow camera usage", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions(FotoPerfil.this, new String[] {Manifest.permission.CAMERA}, MY_REQUEST_CODE); } }); } } else { Log.d("MyApp", "Permission granted: taking pic"); takePicture(); } } else { Log.d("MyApp", "Android < 6.0"); } } 

then

 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(this) .setMessage(message) .setPositiveButton("OK", okListener) .setNegativeButton("Cancel", null) .create() .show(); } 

and then

 @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_REQUEST_CODE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { criarFoto(); } else { Toast.makeText(this, "You did not allow camera usage :(", Toast.LENGTH_SHORT).show(); noFotoTaken(); } return; } } } 

The assumed behavior is that if the user mistakenly checks “Never ask again”, your application gets stuck (the query dialog does not appear) and the user may feel disappointed. Thus, the message tells him that he needs this permission.

+3
Jun 30 '16 at 6:38
source share

I deleted:

 uses-permission android:name="android.permission.CAMERA" 

and relied only on:

 uses-feature android:name="android.hardware.camera" android:required="true" 

in the manifest file.

0
Jun 26 '16 at 8:21
source share

This method does not check only the camera, but all the permissions required by my application at startup ... I have this in my Helper.java file. Also note that I use this library for dialogue: https://github.com/afollestad/material-dialogs

  ///check camera permission public static boolean hasPermissions(final Activity activity){ //add your permissions here String[] AppPermissions = { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; //ungranted permissions ArrayList<String> ungrantedPerms = new ArrayList<String>(); //loop //lets set a boolean of hasUngrantedPerm to false Boolean needsPermRequest = false; //permissionGranted int permGranted = PackageManager.PERMISSION_GRANTED; //permission required content String permRequestStr = activity.getString(R.string.the_following_perm_required); //loop for(String permission : AppPermissions){ //check if perm is granted int checkPerm = ContextCompat.checkSelfPermission(activity,permission); //if the permission is not granted if(ContextCompat.checkSelfPermission(activity,permission) != permGranted){ needsPermRequest = true; //add the permission to the ungranted permission list ungrantedPerms.add(permission); //permssion name String[] splitPerm = permission.split(Pattern.quote(".")); String permName = splitPerm[splitPerm.length-1].concat("\n"); permRequestStr = permRequestStr.concat(permName); }//end if }//end loop //if all permission is granted end exec //then continue code exec if(!needsPermRequest) { return true; }//end if //convert array list to array string final String[] ungrantedPermsArray = ungrantedPerms.toArray(new String[ungrantedPerms.size()]); //show alert Dialog requesting permission new MaterialDialog.Builder(activity) .title(R.string.permission_required) .content(permRequestStr) .positiveText(R.string.enable) .negativeText(R.string.cancel) .onPositive(new MaterialDialog.SingleButtonCallback(){ @Override public void onClick(@NonNull MaterialDialog dialog,@NonNull DialogAction which){ //request the permission now ActivityCompat.requestPermissions(activity,ungrantedPermsArray,0); } }) .show(); //return false so that code exec in that script will not be allowed //to continue return false; }//end checkPermissions 

so you add or remove your permission lists here:

 //add your permissions here String[] AppPermissions = { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; 

In my Activity file, I check the permission like this, the Helper class is where I saved the hasPermissions method

  if(Helper.hasPermissions(this) == false){ return; }//end if 

This means that we do not need to continue execution if permission is not granted. Again we will need to listen to the permission request after it is completed, to do this, add the following code to your activity file (optional)

 //Listen to Permission request completion //put in your activity file @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { int permGranted = PackageManager.PERMISSION_GRANTED; Boolean permissionRequired = false; for(int perm : grantResults){ if(perm != permGranted){ permissionRequired = true; } } //if permission is still required if(permissionRequired){ //recheck and enforce permission again Helper.hasPermissions(this); }//end if }//end method 
0
Mar 17 '17 at 1:33
source share

a little late. but I want to add one more thing. whenever you call methods that contain camera functions, use it in a try catch block. if the application will not work on some devices, such as Moto G4 plus or one plus.

 private static final int CAMERA_REQUEST_CODE = 10; //TODO add camera opening functionality here. try { captureImage(); Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); startActivityForResult(intent,CAMERA_REQUEST_CODE); } catch (Exception e){ e.printStackTrace(); } private void captureImage(){ if( ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(new String[]{android.Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE); } else { // Open your camera here. } } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == CAMERA_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Now user should be able to use camera } else { // Your app will not have this permission. Turn off all functions // that require this permission or it will force close like your // original question } } } 

PS: make sure you don't copy the paste of the overridden method.

0
Jul 24 '17 at 10:56 on
source share

You must enable the permission of the application to use the camera. I prefer to add this method to add a command that activates the camera:

  public static async Task<bool> HasPermission() { var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera); if (status == PermissionStatus.Granted) return true; if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Camera)) { ShowDialogOk("Error", "Please allow access to the camera.");//that is my custom method for allert } var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Camera); status = results[Permission.Camera]; return status == PermissionStatus.Granted; } 
0
Sep 04 '19 at 7:49
source share



All Articles