如何使用ACTION_OPEN_DOCUMENT显示更多提供者

时间:2014-12-19 14:33:07

标签: android android-contentprovider

我想使用作为Storage Access Framework一部分提供的android系统对话框来打开文件。我这样做

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/pdf");
startActivityForResult(intent, EDIT_REQUEST);

然后在onActivityResult()处理返回的URI。

问题在于,在结果菜单中,我得到的内容提供商远远少于我的预期。仅限Google云端硬盘和下载(请参阅下面的左侧屏幕截图)。其他人,如Dropbox,Solid Explorer,......都没有显示。

我怀疑原因是这些应用程序根本没有设置必要的intent过滤器以显示在此列表中。

然而,其他应用程序,例如Kaiten Mail或Chrome,以某种方式设法显示系统对话框,列表顶部的完全实现的内容提供商,然后其他人,如下面的Dropbox和Solid Explorer,由细条分隔(见右侧屏幕截图)。

我怎样才能得到这种行为?

Comparison of the behavior I get (left) and the one I want (right)

2 个答案:

答案 0 :(得分:1)

使用'ACTION_GET_CONTENT:

Intent intent = new Intent(Intent. ACTION_GET_CONTENT);
intent.setType("application/pdf");
startActivityForResult(intent, EDIT_REQUEST);

答案 1 :(得分:0)

我们也遇到了这个问题。看来有多种选择方法。

这是我们所做的:

object ThirdPartyIntentsUtil {
        //    https://medium.com/@louis993546/how-to-ask-system-to-open-intent-to-select-jpg-and-png-only-on-android-i-e-no-gif-e0491af240bf
        //example usage: mainType= "*/*"  extraMimeTypes= arrayOf("image/*", "video/*") - choose all images and videos
        //example usage: mainType= "*/image"  extraMimeTypes= arrayOf("image/jpeg", "image/png") - choose all images of png and jpeg types
        /**note that this only requests to choose the files, but it's not guaranteed that this is what you will get*/
        @JvmStatic
        fun getPickFileIntent(context: Context, mainType: String = "*/*", extraMimeTypes: Array<String>? = null): Intent? {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
                return null
            val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            intent.type = mainType
            if (!extraMimeTypes.isNullOrEmpty())
                intent.putExtra(Intent.EXTRA_MIME_TYPES, extraMimeTypes)
            if (context.packageManager.queryIntentActivities(intent, 0).isNullOrEmpty())
                return null
            return intent
        }

        //    https://github.com/linchaolong/ImagePicker/blob/master/library/src/main/java/com/linchaolong/android/imagepicker/cropper/CropImage.java
        @JvmStatic
        fun getPickFileChooserIntent(
                context: Context, title: CharSequence?, preferDocuments: Boolean = true,includeCameraIntents:Boolean, mainType: String
                , extraMimeTypes: Array<String>? = null, extraIntents: ArrayList<Intent>? = null
        ): Intent? {
            val packageManager = context.packageManager
            var allIntents =
                    getGalleryIntents(packageManager, Intent.ACTION_GET_CONTENT, mainType, extraMimeTypes)
            if (allIntents.isEmpty()) {
                // if no intents found for get-content try pick intent action (Huawei P9).
                allIntents =
                        getGalleryIntents(packageManager, Intent.ACTION_PICK, mainType, extraMimeTypes)
            }
            val cameraIntents = getCameraIntents(packageManager)
            allIntents.addAll(0, cameraIntents)
    //        Log.d("AppLog", "got ${allIntents.size} intents")
            if (allIntents.isEmpty())
                return null
            if (preferDocuments)
                for (intent in allIntents)
                    if (intent.component!!.packageName == "com.android.documentsui")
                        return intent
            if (allIntents.size == 1)
                return allIntents[0]
            var target: Intent? = null
            for ((index, intent) in allIntents.withIndex()) {
                if (intent.component!!.packageName == "com.android.documentsui") {
                    target = intent
                    allIntents.removeAt(index)
                    break
                }
            }
            if (target == null)
                target = allIntents[allIntents.size - 1]
            allIntents.removeAt(allIntents.size - 1)
            // Create a chooser from the main  intent
            val chooserIntent = Intent.createChooser(target, title)
            if (extraIntents != null && extraIntents.isNotEmpty())
                allIntents.addAll(extraIntents)
            // Add all other intents
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toTypedArray<Parcelable>())
            return chooserIntent
        }

        private fun getCameraIntents(packageManager: PackageManager): ArrayList<Intent> {
            val cameraIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
            val listCamera = packageManager.queryIntentActivities(cameraIntent, 0)
            val intents = ArrayList<Intent>()
            for (res in listCamera) {
                val intent = Intent(cameraIntent)
                intent.component = ComponentName(res.activityInfo.packageName, res.activityInfo.name)
                intent.`package` = res.activityInfo.packageName
                intents.add(intent)
            }
            return intents
        }

        /**
         * Get all Gallery intents for getting image from one of the apps of the device that handle
         * images. Intent.ACTION_GET_CONTENT and then Intent.ACTION_PICK
         */
        @TargetApi(Build.VERSION_CODES.KITKAT)
        private fun getGalleryIntents(
                packageManager: PackageManager, action: String,
                mainType: String , extraMimeTypes: Array<String>? = null
        ): ArrayList<Intent> {
            val galleryIntent = if (action == Intent.ACTION_GET_CONTENT)
                Intent(action)
            else
                Intent(action, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
            galleryIntent.type = mainType
            if (!extraMimeTypes.isNullOrEmpty()) {
                galleryIntent.addCategory(Intent.CATEGORY_OPENABLE)
                galleryIntent.putExtra(Intent.EXTRA_MIME_TYPES, extraMimeTypes)
            }
            val listGallery = packageManager.queryIntentActivities(galleryIntent, 0)
            val intents = ArrayList<Intent>()
            for (res in listGallery) {
                val intent = Intent(galleryIntent)
                intent.component = ComponentName(res.activityInfo.packageName, res.activityInfo.name)
                intent.`package` = res.activityInfo.packageName
                intents.add(intent)
            }
            return intents
        }

        @JvmStatic
        fun getMimeType(context: Context, uri: Uri): String? {
            val mimeType: String? = if (ContentResolver.SCHEME_CONTENT == uri.scheme) {
                val cr = context.contentResolver
                cr.getType(uri)
            } else {
                val fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
                MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension.toLowerCase())
            }
            return mimeType
        }

    }

因此,假设您希望选择一个视频文件,则可以这样做:

private val mimeTypeMap = MimeTypeMap.getSingleton()
private val videosMimeTypes = arrayOf(mimeTypeMap.getMimeTypeFromExtension("mkv"), mimeTypeMap.getMimeTypeFromExtension("mp4"), mimeTypeMap.getMimeTypeFromExtension("3gp"))

...
val intentForChoosingVideos = ThirdPartyIntentsUtil .getPickFileChooserIntent(this,null,
            true, "videos/*", videosMimeTypes)
            ?: getPickFileIntent(this, "video/*,", videosMimeTypes)

您当然可以更改它以处理其他文件类型。这是图像文件:

private val mimeTypeMap = MimeTypeMap.getSingleton()
private val imagesMimeTypes = arrayOf(mimeTypeMap.getMimeTypeFromExtension("png"), mimeTypeMap.getMimeTypeFromExtension("jpg"), mimeTypeMap.getMimeTypeFromExtension("webp"))

...
val intentForChoosingImages = ThirdPartyIntentsUtil .getPickFileChooserIntent(this, null,
            true, "image/*", imagesMimeTypes)
            ?: getPickFileIntent(this, "image/*,", imagesMimeTypes)

它将尝试拥有扩展的扩展,如果失败,它将尝试选择要使用的应用。如果失败,它将返回null。

请注意,由于某些原因,“ Google相册”应用程序不允许仅选择视频,因此,如果要包含它,请使用更通用的形式:

    val intentForChoosingVideos = ThirdPartyIntentsUtil.getPickFileChooserIntent(this, null,
            false, true,"*/*", videosMimeTypes)
            ?: ThirdPartyIntentsUtil.getPickFileIntent(this, "video/*,", videosMimeTypes)