rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

android開発 ファイル・ピッカーで取得したディレクトリをContentResolverのクエリーでのディレクトリ指定に使う

2022 Jul. 19.
2022 Jul. 18.

// ファイル・ピッカーによるディレクトリ取得
fun myMain() {
    // ボタンがタップされたら、ファイルピッカーによりディレクトリを取得
    buttonSelectDir.setOnClickListener {
        openFilePicker()
    }
}

private fun openFilePicker() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
        addFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION or
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
            Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
            Intent.FLAG_GRANT_PREFIX_URI_PERMISSION )
    }
    fileLauncherSelectDir.launch(intent)
}

/*
 * ボリューム名文字列とディレクトリパス文字列の取得
 * selectedVolumeDirにContentResolverのMediaStore.Files.FileColumns.VOLUME_NAMEに相当する文字列が格納される
 * selectedRelativeDirにContentResolverのMediaStore.Files.FileColumns.RELATIVE_PATHに相当する文字列が格納される
 */
private val fileLauncherSelectDir = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult() )
    { result -> // 結果を受け取るルーチン
        if (result.resultCode == RESULT_OK) {
            // succeeded.
            // get string of directory
            val selectedDirUri = result.data?.data ?: throw  Exception()

            /*
                uri冒頭の"content://com.android.externalstorage.documents/tree"を削除し、
                エンコードされた /(スラッシュ)を戻す。
                ContentPreviderに合わせ、VolumeとRelativeの文字列を取得する。
                プライマリ・ストレージ文字列は"/external_primary/"に置き換える。
             */
            val selectedDirString = selectedDirUri.toString().
                replaceFirst("content://com.android.externalstorage.documents/tree", "")

            selectedVolumeDir = selectedDirString.
                substring(0, selectedDirString.indexOf("%3A")+3 )
            if (selectedVolumeDir.indexOf("/primary%3A") > -1) {
                // primary volume
                selectedVolumeDir = selectedVolumeDir.replaceFirst("/primary%3A", "external_primary")

            } else if (selectedVolumeDir.indexOf("%3A") > -1) {
                    // SD card
                    selectedVolumeDir = selectedVolumeDir.replaceFirst("/", "").replaceFirst("%3A", "")
            }

            selectedRelativeDir = selectedDirString.
                substring( selectedDirString.indexOf("%3A")).
                replace("%3A", "" )
            if (selectedRelativeDir.indexOf("%2F") > -1) {
                selectedRelativeDir = selectedRelativeDir.replace("%2F", "/")
            }
            // Relativeの末尾を"/"にしておく
            if (selectedRelativeDir.takeLast(1) != "/" ) {
                selectedRelativeDir = selectedRelativeDir + "/"
            }
        } else {
            // failed
        }
    }

private fun selectMediaFromContentProvider() {
        /*
         * get uri of media in the directory
         */
        val contentResolver = this.contentResolver
        val proj = arrayOf(
            MediaStore.Files.FileColumns.MEDIA_TYPE,
            MediaStore.Files.FileColumns.RELATIVE_PATH,
            MediaStore.Files.FileColumns.VOLUME_NAME,
            "_data"
        )

        val selectionClause = "(" +
                MediaStore.Files.FileColumns.MEDIA_TYPE + " = " +
                MediaStore.Files.FileColumns.MEDIA_TYPE_AUDIO +
                " OR " +
                MediaStore.Files.FileColumns.MEDIA_TYPE + " = " +
                MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO +
                ")" +
                " AND " +
                "(" +
                MediaStore.Files.FileColumns.VOLUME_NAME + " LIKE ? " +
                " AND " +
                MediaStore.Files.FileColumns.RELATIVE_PATH + " LIKE ? " +
                ")"

        val selectionArgs = arrayOf(selectedVolumeDir, selectedRelativeDir + "%")

        val query = contentResolver.query(
            MediaStore.Files.getContentUri("external"),
            proj,
            selectionClause,
            selectionArgs,
            null
        )

        val tmpVal2 = query?.count

        query?.use { cursor ->
            if (cursor.count > 0) {
                // とりあえず最初のメディアを取り出してみる
                cursor.moveToFirst()
                val medType =
                    cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MEDIA_TYPE))
                val medPath = cursor.getString(cursor.getColumnIndexOrThrow("_data"))

                // play media
                val mediaIntent = Intent()
                mediaIntent.action = Intent.ACTION_VIEW
                if (medType == 2) {
                    mediaIntent.setDataAndType(Uri.parse(medPath), "audio/*")
                    startActivity(mediaIntent)
                } else if (medType == 3) {
                    mediaIntent.setDataAndType(Uri.parse(medPath), "video/*")
                    startActivity(mediaIntent)
                }
            }
        }
        query?.close()
}


参考ページ
android開発 ContentResolver 音声メディア・動画メディアへのクエリによるメディア情報取得 - rokkonet
android開発 ContentResolver query条件書式 ( selectionClause ) - rokkonet