9
votes

Choisissez parmi le fournisseur Google Photos avec ACTION_GET_CONTENT ou OPEN_DOCUMENT

Je ne sais pas pourquoi cela se produit, mais je ne parviens pas à sélectionner des images auprès du fournisseur Google Photos. Test sur l'API 27.

Avec ACTION_GET_CONTENT

Si j'utilise:

2019-03-02 12:04:34.150 13217-13217/? W/ResourceType: For resource 0x7f02036c, entry index(876) is beyond type entryCount(468)
2019-03-02 12:04:34.151 13217-13217/? W/ResourceType: For resource 0x7f02036c, entry index(876) is beyond type entryCount(468)
2019-03-02 12:04:34.229 2907-16891/? W/MediaExtractor: FAILED to autodetect media content.
2019-03-02 12:04:34.569 10839-10839/? W/ResourceType: ResTable_typeSpec entry count inconsistent: given 468, previously 1330
  • Je peux voir Google Photos parmi le fournisseur
  • Je peux accéder à une image et la sélectionner
  • Ensuite, je suis redirigé vers la liste des fournisseurs (pas vers mon application), comme si le fournisseur s'était écrasé lors d'un essai

Lorsque j'ouvre le fournisseur de photos et que je navigue dans les dossiers, j'en vois beaucoup:

2019-03-02 12:04:15.164 17641-13395/? W/NetworkManagementSocketTagger: untagSocket(120) failed with errno -22
2019-03-02 12:04:22.528 13217-13217/? E/ResourceType: Style contains key with bad entry: 0x01010586
2019-03-02 12:04:22.535 13217-13217/? W/ResourceType: For resource 0x7f020366, entry index(870) is beyond type entryCount(468)

Lorsque je clique sur l'image, je vois ceux-ci:

val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"

Avec ACTION_OPEN_DOCUMENT

Dans ce cas, je ne vois même pas Google Photos dans le tiroir des fournisseurs.

Question h2 >

Comment puis-je résoudre ce problème, de préférence avec ACTION_GET_CONTENT?


16 commentaires

Essayez avec ACTION_PICK


Merci mais je dois utiliser l'un de ces deux et j'aimerais savoir pourquoi cela ne fonctionne pas.


@natario quel appareil vous utilisez?!


@Rahul Nexus 5X, api 27


@natario Le testez-vous sur un émulateur? ou le vrai appareil


@natario Vérifiez également ce lien


C'est un vrai appareil, un Nexus 5X.


Peut-être que c'est un bug. Mais je l'ai testé sur l'émulateur Nexus 5X API 27. qui est identique à votre appareil. Et le code fonctionne également très bien ici. P.S. Rechercher des mises à jour


@natario vérifie ma réponse mise à jour. et faites-moi savoir si vous avez besoin d'explications.


@Rahul onActivityResult n'est jamais appelé car le flux ne retourne pas dans mon application, il reste dans le sélecteur comme je l'ai dit.


@natario je me demande ce qui fait que cela ne fonctionne pas pour vous sur un appareil réel mais sur un émulateur.


@RahulKhurana J'ai vérifié ce code sur le téléphone avec le même modèle que le vôtre et cela fonctionne sans aucun problème. vous acier avez ce problème.


@Alishatergholi OP est confronté à ce problème. J'essaye juste de le résoudre de toute façon


@RahulKhurana s'il vous plaît vérifier mon code, cela fonctionne bien sur Nexus 5X.


@Alishatergholi Ok. Je vais


Je comprends que cela fonctionne pour vous, mais ce n'est toujours pas le cas pour moi.


4 Réponses :


0
votes

Le ACTION_PICK vous donnera la possibilité de choisir l'image et vous pourrez obtenir le chemin du fichier

    Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Image.Media.EXTERNAL_CONTENT_URI);
                    intent.setType("image/*");

                Intent sIntent = new Intent("com.sec.android.app.myfiles.PICK_DATA");
                sIntent.addCategory(Intent.CATEGORY_DEFAULT);
                sIntent.setType("image/*");

                Intent chooserIntent;
                if (getPackageManager().resolveActivity(sIntent, 0) != null) {
                    // it is device with samsung file manager
                    chooserIntent = Intent.createChooser(sIntent, "Select file");
                    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{intent});
                } else {
                    chooserIntent = Intent.createChooser(intent, "Select file");
                }
                try {
                    startActivityForResult(chooserIntent, REQUEST_TAKE_GALLERY_VIDEO);
                } catch (android.content.ActivityNotFoundException ex) {
                    Toast.makeText(getApplicationContext(), "No suitable File Manager was found.", Toast.LENGTH_SHORT).show();
                }


1 commentaires

Merci, mais je ne souhaite pas utiliser ACTION_PICK. J'ai besoin d'utiliser l'un des deux (obtenir le contenu / ouvrir le document).



4
votes

EDIT 2

Je pense avoir trouvé la solution du problème. Il est mentionné dans les documents Google que l'accès à un le fichier partagé vous donnera l ' URI .

L'application serveur renvoie l'URI du contenu du fichier à l'application cliente dans une intention. Cette intention est transmise à l'application cliente dans sa substitution de onActivityResult (). Une fois que l'application cliente a l'URI du contenu du fichier, elle peut accéder au fichier en obtenant son FileDescriptor.

Voici le code mis à jour que j'utilise dans onActivityResult . Assurez-vous d'appeler enfin la méthode super de onActivityResult.

super.onActivityResult (requestCode, resultCode, données)

Code de travail

fun copyInputStreamToFile(`in`: InputStream, file: File) {
    var out: OutputStream? = null
    try {
        out = FileOutputStream(file)
        val buf = ByteArray(1024)
        var len: Int = 0
        while (`in`.read(buf).apply { len = this } > 0) {
            out.write(buf, 0, len)
        }

        /*while (`in`.read(buf).let {
                    len = it
                    true
                }) {
            out.write(buf, 0, len)
        }*/
        /* while ((len = `in`.read(buf)) > 0) {
             out.write(buf, 0, len)
         }*/
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        try {
            out?.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        try {
            `in`.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
}

MODIFIER

Vérifiez également ceci article destackoverflow

Je l'utilise sur Android oreo 8.1.0 (API 27) sur mon téléphone Redmi 6 pro et cela fonctionne très bien.

Vous n'avez pas publié la méthode onActivityResult , c'est peut-être ici vous devez faire quelques modifications. Je l'ai essayé à la fois

Voici mon extrait de code

@Throws(IOException::class)
private fun createImageFile(): File {
    // Create an image file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(Date())
    val imageFileName = "yesqueen_" + timeStamp + "_"
    val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
    return File.createTempFile(imageFileName, ".jpg", storageDir)
}

et dans onActivityResult je l'analyse comme ceci p>

if (data!!.data != null && data.data != null) {
    try {
        //                    CommonUtilities._Log(TAG, "Data Type " + data.getType());
        if (!isFinishing) {
            val inputStream = contentResolver.openInputStream(data.data!!)
            val createFile = createImageFile()
            copyInputStreamToFile(inputStream!!, createFile)
            //                        CommonUtilities._Log(TAG, "File Path " + createFile.getAbsolutePath());
            selectedImagePath = createFile.absolutePath
        }
    } catch (e: IOException) {
        util._log(TAG, Log.getStackTraceString(e))
    }
}

Méthode de création d'un nouveau fichier

val pickIntent = Intent(Intent.ACTION_VIEW)
pickIntent.type = "image/*"
pickIntent.action = Intent.ACTION_GET_CONTENT
pickIntent.addCategory(Intent.CATEGORY_OPENABLE)

startActivityForResult(pickIntent, SELECT_PICTURE)

Méthode de lecture à partir du flux d'entrée

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
data?.data?.let {
    util._log(TAG, it.toString())
}
if (data!!.data != null && data.data != null) {
    try {

        val stream = if (data.data!!.toString().contains("com.google.android.apps.photos.contentprovider")) {
            val ff = contentResolver.openFileDescriptor(data.data!!, "r")
            FileInputStream(ff?.fileDescriptor)
        } else {
            contentResolver.openInputStream(data.data!!)
        }
        val createFile = createImageFile()
        util.copyInputStreamToFile(stream, createFile)
        selectedImagePath = createFile.absolutePath

    } catch (e: Exception) {
        util._log(TAG, Log.getStackTraceString(e))
    }
}
    super.onActivityResult(requestCode, resultCode, data)
}


4 commentaires

Merci, mais onActivityResult n'est jamais appelé car l'appareil ne retourne même pas à mon application. Il revient au sélecteur d'image système (celui avec le tiroir). Donc: application -> sélecteur système -> sélectionnez Google Photos -> choisissez une image -> retour au sélecteur.


Aviez-vous essayé comme dans ma réponse ??


@natario j'ai également joint un GIF qui montre que cela fonctionne :)


Vous avez utilisé les 3 mêmes lignes que dans ma question - ACTION_GET_CONTENT, CATEGORY_OPENABLE et "image / *", donc oui, j'ai essayé. Je pense aussi que ce sont corrects.



1
votes

Je l'ai fait avec ce code.

 fun bitmap(path : String) : Bitmap{
    val image = File(path)
    val bmOptions = BitmapFactory.Options()
    return BitmapFactory.decodeFile(image.absolutePath, bmOptions)
}

et pour résultat

fun generateBitmap(context: Context, uri: Uri): Bitmap? {
    var filePath = ""
    var cursor: Cursor?
    var columnIndex = 0
    try {
        val column = arrayOf(MediaStore.Images.Media.DATA)
        val sel = arrayOf(MediaStore.Images.Media._ID + "=?")
        if (uri.toString().startsWith("content://com.google.android.apps.photos.contentprovider")){
            val content = this.contentResolver.openInputStream(uri) ?: return null
            val pictureBitmap = BitmapFactory.decodeStream(content)
            return pictureBitmap
        } else {
            filePath = ""
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                val wholeID = DocumentsContract.getDocumentId(uri)
                val id = arrayOf(wholeID.split(":")[1])
                cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel[0], id, null)
                columnIndex = cursor.getColumnIndex(column[0])
                if (cursor.moveToFirst()) {
                    filePath = cursor.getString(columnIndex)
                }
                cursor.close()
            } else {
                val cursorLoader = CursorLoader(context, uri, column, null, null, null)
                val cursor = cursorLoader.loadInBackground()
                if (cursor != null) {
                    var column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
                    cursor.moveToFirst()
                    filePath = cursor.getString(column_index)
                }
            }
            //TODO generate bitmap from file path
            return bitmap(filePath)
        }
    } catch (e: Exception) {
        print(e.message)
    }
    return null
}

generateBitmap (context, uri) méthode dans Kotlin

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        100 -> {
            if (resultCode == Activity.RESULT_OK) {
                val bitmap = generateBitmap(this,data!!.data)
                //TODO show bitmap to your View
                showPicture(bitmap!!)
            }
        }
    }
}

pour getBitmap à partir du chemin du fichier J'ai utilisé cette méthode

val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent,100)


1 commentaires

@natario J'ai changé une partie de la réponse, j'espère que cela résoudra votre problème



0
votes

J'ai eu le même problème, je n'ai pas pu obtenir l'URI d'image de Google Photos avec une intention ACTION_GET_CONTENT . Le problème était lié au launchMode de mon activité. Je n'ai trouvé aucune référence aux documentations Android. mais de cette façon, le problème est complètement résolu:

Je n'avais qu'une seule application d'activité et mon intention ACTION_GET_CONTENT ressemblait à ceci:

gallery.setOnClickListener {
    startActivityForResult(
        Intent(requireActivity(), ImagePickerActivity::class.java),
        GALLERY_RESULT
    )
}

le problème était le mode de lancement singleInstance dans la définition de l'activité dans AndroidManifest.xml.

class ImagePickerActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
            type = "image/*"
        }

        if (intent.resolveActivity(packageManager!!) != null) {
            startActivityForResult(intent, GALLERY_RESULT)
        } else {
            Toast.makeText(
                this,
                "No Gallery APP installed",
                Toast.LENGTH_LONG
            ).show()
            finish()
        }

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        //here data is resulted URI from ACTION_GET_CONTENT
        //and we pass it to our MainActivy using setResult
        setResult(resultCode, data)
        finish()
    }
}

En supprimant la ligne android: launchMode, le problème a été résolu. Si votre activité doit être singleInstance , créer une activité factice sera une bonne solution. ici, vous pouvez démarrer une activité factice pour le résultat, puis effectuer vos tâches d'intention dans son onCreate , puis setResult () pour votre activité demandée:

<activity
android:name=".ui.MainActivity"
android:configChanges="orientation"
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateHidden"/>

et voici votre code dans votre MainActivity:

val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
      type = "image/*"
}
startActivityForResult(intent, GALLERY_RESULT)


0 commentaires