Androïde action Image CAPTURE intention

nous essayons d'utiliser l'application caméra native pour permettre à l'utilisateur de prendre une nouvelle photo. Cela fonctionne très bien si nous laissons de côté le EXTRA_OUTPUT extra et retournons la petite image Bitmap. Cependant, si nous putExtra(EXTRA_OUTPUT,...) sur l'intention avant de commencer, tout fonctionne jusqu'à ce que vous essayez d'appuyer sur le bouton "Ok" dans l'application caméra. Le bouton "Ok" juste ne fait rien. L'application caméra reste ouverte et rien ne se bloque. On peut annuler, mais le dossier n'est jamais écrit. Que devons-nous faire exactement pour obtenir ACTION_IMAGE_CAPTURE pour écrire la photo prise dans un fichier?

Edit: Ceci est fait via le MediaStore.ACTION_IMAGE_CAPTURE intention, juste pour être clair

151
demandé sur Alex Cohn 2009-12-16 00:41:29

14 réponses

c'est un bug bien documenté dans certaines versions d'android. c'est, sur l'expérience google versions d'android, la capture d'image ne fonctionne pas comme indiqué. ce que j'ai utilisée est généralement quelque chose comme ça dans une classe d'utilitaires.

public boolean hasImageCaptureBug() {

    // list of known devices that have the bug
    ArrayList<String> devices = new ArrayList<String>();
    devices.add("android-devphone1/dream_devphone/dream");
    devices.add("generic/sdk/generic");
    devices.add("vodafone/vfpioneer/sapphire");
    devices.add("tmobile/kila/dream");
    devices.add("verizon/voles/sholes");
    devices.add("google_ion/google_ion/sapphire");

    return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/"
            + android.os.Build.DEVICE);

}

puis quand je lance image capture, je crée une intention qui vérifie le bogue.

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (hasImageCaptureBug()) {
    i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp")));
} else {
    i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
startActivityForResult(i, mRequestCode);

alors dans l'activité que je retourne à, je fais des choses différentes basées sur le appareil.

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
     switch (requestCode) {
         case GlobalConstants.IMAGE_CAPTURE:
             Uri u;
             if (hasImageCaptureBug()) {
                 File fi = new File("/sdcard/tmp");
                 try {
                     u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null));
                     if (!fi.delete()) {
                         Log.i("logMarker", "Failed to delete " + fi);
                     }
                 } catch (FileNotFoundException e) {
                     e.printStackTrace();
                 }
             } else {
                u = intent.getData();
            }
    }

cela vous évite d'avoir à écrire une nouvelle application caméra, mais ce code n'est pas génial non plus. les grands problèmes sont

  1. les appareils avec le bug. vous obtenez photos qui sont 512px de large que sont insérés dans le contenu de l'image Fournisseur. sur les appareils sans l' bug, tout fonctionne comme document, vous obtenez une grande image normale.

  2. vous devez maintenir la liste. comme écrit, il est possible pour les appareils pour être flashé avec une version de android (dire cyanogenmod est construit ) qui a corrigé le bug. si cela se produit, votre code accident. la solution est d'utiliser l'ensemble de la empreinte digitale de l'appareil.

142
répondu yanokwa 2012-01-18 11:32:07

je sais que cela a été répondu avant, mais je sais que beaucoup de gens trébucher sur ce, je vais donc ajouter un commentaire.

j'ai eu exactement le même problème sur mon Nexus One. C'était à partir du fichier qui n'existait pas sur le disque avant que l'application de caméra ne démarre. Par conséquent, je me suis assuré que le fichier existant avant de démarrer l'application de caméra. Voici un exemple de code que j'ai utilisé:

String storageState = Environment.getExternalStorageState();
        if(storageState.equals(Environment.MEDIA_MOUNTED)) {

            String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg";
            _photoFile = new File(path);
            try {
                if(_photoFile.exists() == false) {
                    _photoFile.getParentFile().mkdirs();
                    _photoFile.createNewFile();
                }

            } catch (IOException e) {
                Log.e(TAG, "Could not create file.", e);
            }
            Log.i(TAG, path);

            _fileUri = Uri.fromFile(_photoFile);
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE );
            intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri);
            startActivityForResult(intent, TAKE_PICTURE);
        }   else {
            new AlertDialog.Builder(MainActivity.this)
            .setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState)
            .setCancelable(true).create().show();
        }

je crée d'abord un nom de fichier unique (quelque peu) utiliser un hachage MD5 et le mettre dans le dossier approprié. Je vérifie ensuite si elle existe (devrait pas, mais sa bonne pratique à vérifier de toute façon). Si elle n'existe pas, j'obtiens le dir parent (un dossier) et je crée la hiérarchie de dossiers jusqu'à elle (donc si les dossiers menant à l'emplacement du fichier n'existent pas, ils le feront après cette ligne. Puis, après que j'ai créer le fichier. Une fois que le fichier est créé, je reçois L'Uri et le passe à l'intention et puis le bouton OK fonctionne comme prévu et tout est Golden.

Maintenant, lorsque le bouton Ok est appuyé sur l'application caméra, le fichier sera présent dans l'emplacement donné. Dans cet exemple, il s'agirait de /sdcard/Android/data/com.exemple.myapp/fichiers/234asdioue23498ad.jpg

Il n'est pas nécessaire de copier le fichier dans le "onActivityResult" comme affiché ci-dessus.

50
répondu Donn Felker 2011-02-20 01:17:07

j'ai été à travers un certain nombre de stratégies de capture de photos, et il semble toujours y avoir un cas, une plate-forme ou certains dispositifs, où certaines ou toutes les stratégies ci-dessus vont échouer de manière inattendue. J'ai pu trouver une stratégie qui utilise le code de génération URI ci-dessous qui semble fonctionner dans la plupart sinon tous les cas.

mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
            new ContentValues());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER);

pour contribuer davantage à la discussion et aider les nouveaux venus j'ai créé un échantillon / test application qui montre plusieurs différents stratégies pour la capture de photos de la mise en œuvre. Les Contributions d'autres implémentations sont certainement encouragés à ajouter à la discussion.

https://github.com/deepwinter/AndroidCameraTester

31
répondu deepwinter 2013-06-12 02:24:05

j'ai eu le même problème où le bouton OK dans l'application camera n'a rien fait, à la fois sur l'émulateur et sur nexus one.

le problème a disparu après avoir spécifié un nom de fichier sûr qui est sans espaces blancs, sans caractères spéciaux, dans MediaStore.EXTRA_OUTPUT aussi, si vous spécifiez un fichier qui réside dans un répertoire qui n'a pas encore été créé, vous devez le créer en premier. L'application caméra ne fait pas mkdir pour vous.

29
répondu Yenchi 2012-06-27 13:11:03

le flux de travail que vous décrivez devrait fonctionner comme vous l'avez décrit. Il pourrait être utile si vous pouviez nous montrer le code autour de la création de l'Intention. En général, le modèle suivant devrait vous permettre de faire ce que vous essayez.

private void saveFullImage() {
  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
  outputFileUri = Uri.fromFile(file);
  intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
  startActivityForResult(intent, TAKE_PICTURE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if ((requestCode == TAKE_PICTURE) && (resultCode == Activity.RESULT_OK)) {
    // Check if the result includes a thumbnail Bitmap
    if (data == null) {    
      // TODO Do something with the full image stored
      // in outputFileUri. Perhaps copying it to the app folder
    }
  }
}

notez que C'est l'activité Caméra qui va créer et sauvegarder le fichier, et ce n'est pas réellement une partie de votre application, donc il n'aura pas la permission d'écrire dans votre dossier d'application. Pour sauvegarder un fichier dans votre dossier app, créez un fichier temporaire sur la carte SD et déplacez-le dans votre dossier app dans le gestionnaire onActivityResult .

28
répondu Reto Meier 2009-12-15 22:38:27

pour suivre le commentaire de Yenchi ci-dessus, le bouton OK ne fera rien si l'application caméra ne peut pas écrire dans le répertoire en question.

cela signifie que vous ne pouvez pas créer le fichier dans un endroit qui est seulement writable par votre demande (par exemple, quelque chose sous getCacheDir()) quelque chose sous getExternalFilesDir() devrait fonctionner, cependant.

ce serait bien si l'application caméra imprimait un message d'erreur sur les logs si elle ne pouvait pas écrire spécifié EXTRA_OUTPUT chemin, mais je n'en ai pas trouvé.

7
répondu Joe 2012-06-27 13:10:16

pour que la caméra écrive sur sdcard mais garde un nouvel Album sur l'application gallery j'utilise ceci:

 File imageDirectory = new File("/sdcard/signifio");
          String path = imageDirectory.toString().toLowerCase();
           String name = imageDirectory.getName().toLowerCase();


            ContentValues values = new ContentValues(); 
            values.put(Media.TITLE, "Image"); 
            values.put(Images.Media.BUCKET_ID, path.hashCode());
            values.put(Images.Media.BUCKET_DISPLAY_NAME,name);

            values.put(Images.Media.MIME_TYPE, "image/jpeg");
            values.put(Media.DESCRIPTION, "Image capture by camera");
           values.put("_data", "/sdcard/signifio/1111.jpg");
         uri = getContentResolver().insert( Media.EXTERNAL_CONTENT_URI , values);
            Intent i = new Intent("android.media.action.IMAGE_CAPTURE"); 

            i.putExtra(MediaStore.EXTRA_OUTPUT, uri);

            startActivityForResult(i, 0); 

veuillez noter que vous devrez générer un nom de fichier unique à chaque fois et remplacer teh 1111.jpg que j'ai écrit. Ceci a été testé avec nexus one. l'uri est déclaré dans la classe privée, donc sur le résultat de l'activité je suis en mesure de charger l'image de l'uri à imageView pour l'aperçu si nécessaire.

4
répondu nabulaer 2010-06-29 08:01:37

je vous recommande de suivre le post de formation android pour capturer une photo. Ils montrent dans un exemple comment prendre des photos petites et grandes. Vous pouvez également télécharger le code source de ici

2
répondu JuanVC 2012-06-27 13:10:35

j'ai eu le même problème et je l'ai corrigé avec le suivant:

Le problème est que lorsque vous spécifiez un fichier seulement votre application a accès (par exemple, en appelant getFileStreamPath("file"); )

c'est pourquoi je me suis assuré que le fichier existe vraiment et que tout le monde y a accès en écriture.

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File outFile = getFileStreamPath(Config.IMAGE_FILENAME);
outFile.createNewFile();
outFile.setWritable(true, false);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,Uri.fromFile(outFile));
startActivityForResult(intent, 2);

de cette façon, l'application de caméra a un accès en écriture à L'Uri donné et le bouton OK fonctionne très bien :)

1
répondu Goddchen 2011-03-28 16:08:50

Il est très simple de résoudre ce problème avec l'Activité Code de Résultat Simple d'essayer cette méthode

if (reqCode == RECORD_VIDEO) {
   if(resCode == RESULT_OK) {
       if (uri != null) {
           compress();
       }
    } else if(resCode == RESULT_CANCELED && data!=null){
       Toast.makeText(MainActivity.this,"No Video Recorded",Toast.LENGTH_SHORT).show();
   }
}
1
répondu Savita 2016-05-01 14:12:53

j'ai créé bibliothèque simple qui va gérer le choix des images de différentes sources (Galerie, Appareil photo), peut-être le sauver à un certain endroit (SD - carte ou la mémoire interne) et retourner l'image en arrière donc s'il vous plaît libre de l'utiliser et de l'améliorer- Android-ImageChooser .

0
répondu svenkapudija 2012-11-24 19:20:28

le dossier doit pouvoir être écrit par la caméra, comme Praveen l'a souligné.

dans mon usage je voulais stocker le fichier dans le stockage interne. Je l'ai fait avec:

Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (i.resolveActivity(getPackageManager()!=null)){
    try{
        cacheFile = createTempFile("img",".jpg",getCacheDir());
        cacheFile.setWritavle(true,false);
    }catch(IOException e){}
    if(cacheFile != null){
        i.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(cacheFile));
        startActivityForResult(i,REQUEST_IMAGE_CAPTURE);
    }
}

Ici cacheFile est un fichier global utilisé pour désigner le fichier qui est écrit. Puis dans la méthode de résultat l'intention retournée est nulle. Alors la méthode pour traiter l'intention ressemble à:

protected void onActivityResult(int requestCode,int resultCode,Intent data){
    if(requestCode != RESULT_OK){
        return;
    }
    if(requestCode == REQUEST_IMAGE_CAPTURE){
        try{
            File output = getImageFile();
            if(output != null && cacheFile != null){
                copyFile(cacheFile,output);

                //Process image file stored at output

                cacheFile.delete();
                cacheFile=null;
            }
        }catch(IOException e){}
    }
}

ici getImageFile() est une méthode utilitaire de nom et de créer le fichier dans lequel l'image doit être stockée, et copyFile() est une méthode pour copier un fichier.

0
répondu Duncan 2017-05-23 11:47:16

vous pouvez utiliser ce code

private Intent getCameraIntent() {

    PackageManager packageManager = mContext.getPackageManager();
    List<ApplicationInfo> list = packageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
    Intent main = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    List<ResolveInfo> launchables = packageManager.queryIntentActivities(main, 0);
    if (launchables.size() == 1)
        return packageManager.getLaunchIntentForPackage(launchables.get(0).activityInfo.packageName);
    else
        for (int n = 0; n < list.size(); n++) {
            if ((list.get(n).flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
                Log.d("TAG", "Installed Applications  : " + list.get(n).loadLabel(packageManager).toString());
                Log.d("TAG", "package name  : " + list.get(n).packageName);
                String defaultCameraPackage = list.get(n).packageName;


                if (launchables.size() > 1)
                    for (int i = 0; i < launchables.size(); i++) {
                        if (defaultCameraPackage.equals(launchables.get(i).activityInfo.packageName)) {
                            return packageManager.getLaunchIntentForPackage(defaultCameraPackage);
                        }
                    }
            }
        }
    return null;
}
0
répondu Ngông Cuồng 2015-10-21 04:41:52
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_CANCELED)
    {
        //do not process data, I use return; to resume activity calling camera intent
        enter code here
    }
}
0
répondu Ajesh Gupta 2017-06-20 09:44:38