wake-up-neo.com

Android M Camera Intent + Berechtigungsfehler?

Ich versuche, meine App für die neuen Android= M-Berechtigungsänderungen vorzubereiten und habe komisches Verhalten festgestellt. Meine App verwendet den Kamera-Intent-Mechanismus, damit der Benutzer ein Bild von der Kamera abrufen kann. In einer anderen Aktivität muss jedoch die Kamera selbst mit Kameraberechtigung verwendet werden (aufgrund einer Bibliotheksabhängigkeit card.io, die dies erfordert).

Mit M in der Aktivität, die nur eine Kameraabsicht benötigt, wenn ich versuche, die Kameraabsicht zu starten, wird jedoch der folgende Absturz angezeigt (dies geschieht nicht, wenn ich die Kameraberechtigung aus dem Manifest entferne).

> 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

Ist das ein bekanntes Problem mit Android M? Und was noch wichtiger ist, wie kann ich das umgehen?

im Manifest habe ich Folgendes:

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

mit diesem Code kann der Benutzer mit der Kamera auf ein Bild klicken und/oder ein Bild auswählen

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

Ich rufe die Funktion openImageIntent() auf, wenn ich in meiner Aktivität auf eine Schaltfläche klicke. Wenn ich die CAMERA-Berechtigung nicht in meiner App habe, funktioniert es einwandfrei, aber mit dieser zusätzlichen Berechtigung erhalte ich die oben angegebene Ausnahme.

    @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
source.rar

Ich hatte das gleiche Problem und fand dieses Dokument bei Google: https://developer.Android.com/reference/Android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE

"Hinweis: Wenn Sie App-Ziele ab M verwenden und angeben, dass die nicht erteilte CAMERA-Berechtigung verwendet wird, führt der Versuch, diese Aktion zu verwenden, zu einer SecurityException."

Das ist wirklich komisch. Macht überhaupt keinen Sinn. Die App erklärt die Kameraberechtigung mit Absicht mit der Aktion IMAGE_CAPTURE und ruft SecurityException auf. Wenn Ihre App die Kameraberechtigung jedoch nicht mit Absicht mit Aktion deklariert, kann IMAGE_CAPTURE die Kamera-App ohne Probleme starten.

Die Problemumgehung besteht darin, zu überprüfen, ob die App über Kameraberechtigungen im Manifest verfügt. Wenn dies der Fall ist, fordern Sie die Kameraberechtigungen an, bevor Sie die Absicht starten.

Auf diese Weise können Sie überprüfen, ob die Berechtigung im Manifest enthalten ist, unabhängig davon, ob die Berechtigung erteilt wurde oder nicht.

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
luna

Wenn Sie das Berechtigungsmodell Android M verwenden, müssen Sie zuerst überprüfen, ob die App zur Laufzeit über diese Berechtigung verfügt, und den Benutzer zur Laufzeit zur Eingabe dieser Berechtigung auffordern. Die in Ihrem Manifest definierte Berechtigung wird bei der Installation nicht automatisch erteilt.

if (checkSelfPermission(Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED) {

    requestPermissions(new String[]{Manifest.permission.CAMERA},
            MY_REQUEST_CODE);
}

MY_REQUEST_CODE ist eine statische Konstante, die Sie definieren können und die erneut für den Rückruf des requestPermission-Dialogfelds verwendet wird.

Sie benötigen einen Rückruf für das Dialogergebnis:

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

bearbeiten

Beim Lesen aus dem Stack-Trace scheint für Google Camera die CAMERA-Berechtigung nicht aktiviert zu sein. Dies könnte tatsächlich nach einer Abwärtskompatibilitätssache aussehen.

Nehmen wir an, dass Google Camera (oder eine andere Anwendung, die Ihre ACTION-Absicht behandelt) eine bestimmte Berechtigung benötigt.

Wenn Ihre App nicht über die CAMERA-Berechtigung verfügt, lässt sie nur Google Camera mit dem alten Berechtigungsmodell arbeiten.

Mit der in Ihrem Manifest deklarierten CAMERA-Berechtigung wird jedoch auch die CAMERA-Berechtigung in Google Camera (die nicht über das Berechtigungsmodell Android M verfügt) erzwungen, um das Berechtigungsmodell Android M zu verwenden (glaube ich). )

Wenn Sie also die oben beschriebene Methode verwenden, müssen Sie Ihre App-Berechtigung zur Laufzeit bereitstellen. Die untergeordnete Aufgabe (in diesem Fall Google Camera) verfügt nun auch über diese Berechtigung.

20
JTY

Soweit Ihre Frage "Ist das ein bekanntes Problem in M?" Ein Google-Entwickler hat auf einen Fehler geantwortet, der dieses Problem gemeldet hat.

Siehe hier: https://code.google.com/p/Android/issues/detail?id=188073&q=label%3APriority-Medium&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&start=1 =

Hier ist das Wort von Google: „Mit diesem Verhalten soll vermieden werden, dass Benutzer frustriert werden, wenn sie die Kameraberechtigung für eine App widerrufen und die App weiterhin Fotos über die Absicht aufnehmen kann. Benutzern ist nicht bekannt, dass das nach dem Widerruf der Berechtigung aufgenommene Foto über einen anderen Mechanismus erfolgt und die Richtigkeit des Berechtigungsmodells in Frage stellen würde. Dies gilt für MediaStore.ACTION_IMAGE_CAPTURE, MediaStore.ACTION_VIDEO_CAPTURE und Intent.ACTION_CALL die Dokumente, für die das Verhalten für Apps geändert wurde, die auf M ausgerichtet sind. "

Da es Google nichts ausmacht, die Mechanismen für die Verwendung der Kamera von Ihrem Nutzer zu abstrahieren, können Sie auch die erste Anfrage nach Kameraberechtigung strategisch auslösen und auf die Funktionalität der Aktivität verweisen, in der die Kamera als Begründung für die Anfrage verwendet wird. Wenn Sie zulassen, dass Ihre App diese Erlaubnisanforderung zum ersten Mal stellt, wenn der Benutzer lediglich versucht, ein Bild aufzunehmen, kann es sein, dass der Benutzer der Ansicht ist, dass sich Ihre App seltsam verhält, da für das Aufnehmen eines Fotos normalerweise keine Erlaubnis erforderlich ist.

15
A.Sanchez.SD

Wenn Sie Google M verwenden, gehen Sie zu Einstellungen -> Apps -> Ihrer App -> und geben Sie die entsprechenden Berechtigungen.

10
Eduardo Dennis

Ich blieb bei diesem Problem stecken und habe bereits die Antwort von JTY verwendet. Das Problem ist, dass der Anforderungsberechtigungsdialog irgendwann auf "Nie wieder fragen" gesetzt wurde. Ich entwickle auf SDK 24.

Mein vollständiger Code zum Verarbeiten von Berechtigungen (die Kamera in meinem Fall) lautete wie folgt:

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

dann

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

und dann

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

Das beabsichtigte Verhalten ist, dass im Falle, dass der Benutzer versehentlich "Nie wieder fragen" aktiviert hat, Ihre App hängen bleibt (der Anforderungsdialog wird nicht angezeigt) und der Benutzer sich möglicherweise frustriert fühlt. Auf diese Weise teilt ihm eine Nachricht mit, dass er diese Erlaubnis benötigt.

3
Teo Inke

es ist ein bisschen spät. aber ich möchte noch eins hinzufügen. Wenn Sie Methoden aufrufen, die Kamerafunktionalität enthalten, verwenden Sie diese in try catch block. Wenn nicht, stürzt die App auf einigen Geräten wie Moto G4 Plus oder One Plus ab.

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: Stellen Sie sicher, dass Sie die überschriebene Methode nicht kopieren oder einfügen.

0

Ich entfernte:

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

und verließ sich nur auf:

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

in der Manifestdatei.

0

Sie müssen die App-Berechtigung für die Kameranutzung aktivieren. Ich bevorzuge diese Methode hinzufügen Befehl hinzufügen, die Kamera aktivieren:

    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
nzrytmn

Diese meiner Methoden prüft nicht nur auf Kamera, sondern auf alle Berechtigungen, die meine App beim Start benötigt ... Ich habe diese in meiner Helper.Java-Datei. Beachten Sie auch, dass ich für den Dialog diese Bibliothek verwende: 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 können Sie Ihre Berechtigungslisten hier hinzufügen oder entfernen:

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

In meiner Aktivitätsdatei überprüfe ich die Berechtigung wie folgt: In der Helper-Klasse habe ich die hasPermissions-Methode gespeichert

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

Bedeutet, dass wir die Ausführung nicht fortsetzen müssen, wenn keine Berechtigung erteilt wurde. Wieder müssen wir die Berechtigungsanforderung abhören, nachdem sie abgeschlossen wurde. Fügen Sie dazu den folgenden Code zu Ihrer Aktivitätsdatei hinzu (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
razzbee