[android] Comment obtenir le résultat d'une caméra sous forme d'uri dans un dossier de données?


Answers

La meilleure solution que j'ai trouvée est: FileProvider (nécessite support-library-v4) Il utilise le stockage interne! FileProvider

  1. Définissez votre FileProvider dans Manifest dans l'élément Application:

    <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="your.package.name.fileprovider"
          android:exported="false"
          android:grantUriPermissions="true" >
          <meta-data
                     android:name="android.support.FILE_PROVIDER_PATHS"
                     android:resource="@xml/image_path" />
    </provider>
    
  2. Ajouter des autorisations dans l'élément racine du manifeste:

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  3. Définissez vos chemins d'image dans res / xml / image_path.xml par exemple:

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="captured_image" path="your/path/"/>
    </paths>
    
  4. Java:

    private static final int IMAGE_REQUEST_CODE = 1;
    // your authority, must be the same as in your manifest file 
    private static final String CAPTURE_IMAGE_FILE_PROVIDER = "your.package.name.fileprovider";
    

4.1 intention de capture:

    File path = new File(activity.getFilesDir(), "your/path");
    if (!path.exists()) path.mkdirs();
    File image = new File(path, "image.jpg");
    Uri imageUri = FileProvider.getUriForFile(activity, CAPTURE_IMAGE_FILE_PROVIDER, image);
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    startActivityForResult(intent, IMAGE_REQUEST_CODE);

4.2 onActivityResult ():

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == IMAGE_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                File path = new File(getFilesDir(), "your/path");
                if (!path.exists()) path.mkdirs();
                File imageFile = new File(path, "image.jpg");
                // use imageFile to open your image
            }
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }
Question

Je crée une application dans laquelle je veux capturer une image, puis je veux envoyer cette image dans le courriel en pièce jointe.

EXTRA_OUTPUT une caméra en utilisant l'action d'intention android.provider.MediaStore.ACTION_IMAGE_CAPTURE et je passe l'Uri du fichier en tant que paramètre EXTRA_OUTPUT pour récupérer l'image dans le fichier. Cela fonctionne parfaitement et je suis capable d'obtenir l'image capturée si j'utilise l' external storage uri comme EXTRA_OUTPUT mais si j'utilise le dossier de données uri cela ne fonctionne pas et la caméra ne se ferme pas et tous ses boutons ne fonctionnent pas.

Voici mon code pour obtenir le résultat dans le répertoire de stockage externe

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File out = Environment.getExternalStorageDirectory();
out = new File(out, imagename);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(i, CAMERA_RESULT);

Et ce code est pour obtenir l'image dans le dossier de données

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File out = getFilesDir();
out = new File(out, MyPharmacyOptions.PRESCRIPTION_IMAGE_NAME);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(i, CAMERA_RESULT);

J'ai su que le dossier de données n'est pas accessible à la troisième application ainsi peut être ceci cause un problème ainsi j'ai créé un fournisseur de contenu pour partager le dossier.

Voici mon contenu fournir classe

public class MyContentProvider extends ContentProvider {
    private static final String Tag = RingtonContentProvider.class.getName();
    public static final Uri CONTENT_URI = Uri
            .parse("content://x.y.z/");
    private static final HashMap<String, String> MIME_TYPES = new HashMap<String, String>();

    static {
        MIME_TYPES.put(".mp3", "audio/mp3");
        MIME_TYPES.put(".wav", "audio/mp3");
        MIME_TYPES.put(".jpg", "image/jpeg");
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public String getType(Uri uri) {
        String path = uri.toString();

        for (String extension : MIME_TYPES.keySet()) {
            if (path.endsWith(extension)) {
                return (MIME_TYPES.get(extension));
            }
        }

        return (null);
    }

    @Override
    public ParcelFileDescriptor openFile(Uri uri, String mode)
            throws FileNotFoundException {
        File f = new File(getContext().getFilesDir(), uri.getPath());

        if (f.exists()) {
            return (ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY));
        }

        throw new FileNotFoundException(uri.getPath());
    }

    @Override
    public Cursor query(Uri url, String[] projection, String selection,
            String[] selectionArgs, String sort) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public Uri insert(Uri uri, ContentValues initialValues) {
        File file = new File(getContext().getFilesDir(), uri.getPath());
        if(file.exists()) file.delete();
        try {
            file.createNewFile();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return Uri.fromFile(file);
    }

    @Override
    public int update(Uri uri, ContentValues values, String where,
            String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
    }

    @Override
    public int delete(Uri uri, String where, String[] whereArgs) {
        File f = new File(getContext().getFilesDir(), "image1.jpg");
        if(f.exists()) f.delete();
        f = new File(getContext().getFilesDir(), "image2.jpg");
        if(f.exists()) f.delete();

        getContext().getContentResolver().notifyChange(CONTENT_URI, null);

    }
}

Donc, pour utiliser ce contenu, j'utilise le code suivant pour transmettre l'uri à l'activité caméra

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = MyContentProvider.CONTENT_URI;
uri = Uri.withAppendedPath(uri, imagename);
getContentResolver().insert(uri, null);
getContentResolver().notifyChange(RingtonContentProvider.CONTENT_URI, null);
Log.d(Tag, uri.toString());
i.putExtra(MediaStore.EXTRA_OUTPUT, uri);

startActivityForResult(i, CAMERA_RESULT);

Maintenant, si je passe l'url autre que le répertoire de stockage externe, la caméra s'ouvre mais elle ne se ferme pas dans l'émulateur mais dans l'appareil la caméra va se fermer mais je n'obtiens pas le résultat.

J'ai déclaré que ce contenu est fourni dans le fichier manifeste

<provider
android:name=".contentproviders.MyContentProvider"
android:authorities="x.y.z" />

J'ai également donné la permission d' écrire le stockage externe et aussi pour utiliser l'appareil photo .

Je suis capable de capturer l'image en utilisant le stockage externe mais je veux stocker l'image dans le répertoire de données au lieu du stockage externe parce que si le stockage externe n'est pas disponible je veux capturer l'image et vouloir envoyer le courrier.

Si je crée du contenu, je peux aussi partager mon image avec l'application de messagerie.

Si nous ne fournissons pas les extras avec l'intention de la caméra, l'image sera renvoyée comme octet [] dans le résultat de l'activité en tant que donnée supplémentaire, mais pour la vignette, je ne peux pas obtenir l'image haute résolution .




Après avoir recherché ce bug pendant un certain temps, j'ai remarqué que l'activité qui a appelé l'intention de la caméra ne redémarre que lorsque le téléphone est à court de mémoire. donc, parce que l'activité est redémarrée, l'objet contenant le chemin ou Uri vers l'image capturée est actualisé (annulé)

donc je vous suggère d'attraper / détecter l'objet nul dans le onActivityResult, et invite l'utilisateur à libérer de l'espace sur leur appareil ou redémarrer leur téléphone pour une solution temporaire rapide.




Au début, sauvegardez la photo dans votre espace de stockage externe et essayez-la -

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
   this.imageView = (ImageView)this.findViewById(R.id.imageView1);
   Button photoButton = (Button) this.findViewById(R.id.button1);
   photoButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
        startActivityForResult(cameraIntent, CAMERA_REQUEST); 
    }
});
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
   if (requestCode == CAMERA_REQUEST) {  
        Bitmap bmp = intent.getExtras().get("data");
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

         bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
         byte[] byteArray = stream.toByteArray(); // convert camera photo to byte array

         // save it in your external storage.
        FileOutputStream fo = new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/_camera.png"));

        fo.write(byteArray);
        fo.flush();
        fo.close();
   }  
} 

Cible suivante -

File cameraFile = new File(Environment.getExternalStorageDirectory() + "/_camera.png");                 
startActivityForResult(Intent.createChooser(new Intent(Intent.ACTION_SEND)
        .setType("image/jpg")
        .putExtra(Intent.EXTRA_SUBJECT, "Subject")
        .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(cameraFile))
        .putExtra(Intent.EXTRA_TEXT, textBody), "Send your message using"), Constant.EMAIL);





Links