SubwayTooter-Android-App/app/src/main/java/jp/juggler/util/StorageUtils.kt

326 lines
9.3 KiB
Kotlin

package jp.juggler.util
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.OpenableColumns
import android.webkit.MimeTypeMap
import org.apache.commons.io.IOUtils
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.util.*
// internal object StorageUtils{
//
// private val log = LogCategory("StorageUtils")
//
// private const val PATH_TREE = "tree"
// private const val PATH_DOCUMENT = "document"
//
// internal class FileInfo(any_uri : String?) {
//
// var uri : Uri? = null
// private var mime_type : String? = null
//
// init {
// if(any_uri != null) {
// uri = if(any_uri.startsWith("/")) {
// Uri.fromFile(File(any_uri))
// } else {
// any_uri.toUri()
// }
// val ext = MimeTypeMap.getFileExtensionFromUrl(any_uri)
// if(ext != null) {
// mime_type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase(Locale.JAPAN))
// }
// }
// }
// }
//
// private fun getSecondaryStorageVolumesMap(context : Context) : Map<String, String> {
// val result = HashMap<String, String>()
// try {
// val sm = context.applicationContext.getSystemService(Context.STORAGE_SERVICE) as? StorageManager
// if(sm == null) {
// log.e("can't get StorageManager")
// } else {
//
// // SDカードスロットのある7.0端末が手元にないから検証できない
// // if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ){
// // for(StorageVolume volume : sm.getStorageVolumes() ){
// // // String path = volume.getPath();
// // String state = volume.getState();
// //
// // }
// // }
//
// val getVolumeList = sm.javaClass.getMethod("getVolumeList")
// val volumes = getVolumeList.invoke(sm)
// log.d("volumes type=%s", volumes.javaClass)
//
// if(volumes is ArrayList<*>) {
// //
// for(volume in volumes) {
// val volume_clazz = volume.javaClass
//
// val path = volume_clazz.getMethod("getPath").invoke(volume) as? String
// val state = volume_clazz.getMethod("getState").invoke(volume) as? String
// if(path != null && state == "mounted") {
// //
// val isPrimary = volume_clazz.getMethod("isPrimary").invoke(volume) as? Boolean
// if(isPrimary == true) result["primary"] = path
// //
// val uuid = volume_clazz.getMethod("getUuid").invoke(volume) as? String
// if(uuid != null) result[uuid] = path
// }
// }
// }
// }
// } catch(ex : Throwable) {
// log.trace(ex)
// }
//
// return result
// }
//
// private fun isExternalStorageDocument(uri : Uri) : Boolean {
// return "com.android.externalstorage.documents" == uri.authority
// }
//
// private fun getDocumentId(documentUri : Uri) : String {
// val paths = documentUri.pathSegments
// if(paths.size >= 2 && PATH_DOCUMENT == paths[0]) {
// // document
// return paths[1]
// }
// if(paths.size >= 4 && PATH_TREE == paths[0]
// && PATH_DOCUMENT == paths[2]) {
// // document in tree
// return paths[3]
// }
// if(paths.size >= 2 && PATH_TREE == paths[0]) {
// // tree
// return paths[1]
// }
// throw IllegalArgumentException("Invalid URI: $documentUri")
// }
// fun getFile(context : Context, path : String) : File? {
// try {
// if(path.startsWith("/")) return File(path)
// val uri = path.toUri()
// if("file" == uri.scheme) return File(uri.path!!)
//
// // if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT )
// run {
// if(isExternalStorageDocument(uri)) {
// try {
// val docId = getDocumentId(uri)
// val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
// if(split.size >= 2) {
// val uuid = split[0]
// if("primary".equals(uuid, ignoreCase = true)) {
// return File(Environment.getExternalStorageDirectory().toString() + "/" + split[1])
// } else {
// val volume_map =
// getSecondaryStorageVolumesMap(
// context
// )
// val volume_path = volume_map[uuid]
// if(volume_path != null) {
// return File(volume_path + "/" + split[1])
// }
// }
// }
// } catch(ex : Throwable) {
// log.trace(ex)
// }
//
// }
// }
// // MediaStore Uri
// context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
// if(cursor.moveToFirst()) {
// val col_count = cursor.columnCount
// for(i in 0 until col_count) {
// val type = cursor.getType(i)
// if(type != Cursor.FIELD_TYPE_STRING) continue
// val name = cursor.getColumnName(i)
// val value = cursor.getStringOrNull(i)
// if(value != null && value.isNotEmpty() && "filePath" == name) return File(value)
// }
// }
// }
// } catch(ex : Throwable) {
// log.trace(ex)
// }
//
// return null
// }
//
//
//
//}
private const val MIME_TYPE_APPLICATION_OCTET_STREAM = "application/octet-stream"
private val mimeTypeExMap : HashMap<String, String> by lazy {
val map = HashMap<String, String>()
map["BDM"] = "application/vnd.syncml.dm+wbxml"
map["DAT"] = ""
map["TID"] = ""
map["js"] = "text/javascript"
map["sh"] = "application/x-sh"
map["lua"] = "text/x-lua"
map
}
@Suppress("unused")
fun getMimeType(log : LogCategory?, src : String) : String {
var ext = MimeTypeMap.getFileExtensionFromUrl(src)
if(ext != null && ext.isNotEmpty()) {
ext = ext.lowercase()
//
var mime_type : String? = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext)
if(mime_type?.isNotEmpty() == true) return mime_type
//
mime_type = mimeTypeExMap[ext]
if(mime_type?.isNotEmpty() == true) return mime_type
// 戻り値が空文字列の場合とnullの場合があり、空文字列の場合は既知なのでログ出力しない
if(mime_type == null && log != null) {
log.w("getMimeType(): unknown file extension '%s'", ext)
}
}
return MIME_TYPE_APPLICATION_OCTET_STREAM
}
fun getDocumentName(contentResolver : ContentResolver, uri : Uri) : String {
val errorName = "no_name"
return contentResolver.query(uri, null, null, null, null, null)
?.use { cursor ->
return if(! cursor.moveToFirst()) {
errorName
} else {
cursor.getStringOrNull(OpenableColumns.DISPLAY_NAME) ?: errorName
}
}
?: errorName
}
fun getStreamSize(bClose : Boolean, inStream : InputStream) : Long {
try {
var size = 0L
while(true) {
val r = IOUtils.skip(inStream, 16384)
if(r <= 0) break
size += r
}
return size
} finally {
@Suppress("DEPRECATION")
if(bClose) IOUtils.closeQuietly(inStream)
}
}
//fun File.loadByteArray() : ByteArray {
// val size = this.length().toInt()
// val data = ByteArray(size)
// FileInputStream(this).use { inStream ->
// val nRead = 0
// while(nRead < size) {
// val delta = inStream.read(data, nRead, size - nRead)
// if(delta <= 0) break
// }
// return data
// }
//}
fun Context.loadRawResource(resId : Int) : ByteArray {
resources.openRawResource(resId).use { inStream ->
val bao = ByteArrayOutputStream(inStream.available())
IOUtils.copy(inStream, bao)
return bao.toByteArray()
}
}
fun intentOpenDocument(mimeType : String) : Intent {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = mimeType // "image/*"
return intent
}
fun intentGetContent(
allowMultiple : Boolean,
caption : String,
mimeTypes : Array<out String>
) : Intent {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
if(allowMultiple) {
// EXTRA_ALLOW_MULTIPLE は API 18 (4.3)以降。ACTION_GET_CONTENT でも ACTION_OPEN_DOCUMENT でも指定できる
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
// EXTRA_MIME_TYPES は API 19以降。ACTION_GET_CONTENT でも ACTION_OPEN_DOCUMENT でも指定できる
intent.putExtra("android.intent.extra.MIME_TYPES", mimeTypes)
intent.type = when {
mimeTypes.size == 1 -> mimeTypes[0]
// On Android 6.0 and above using "video/* image/" or "image/ video/*" type doesn't work
// it only recognizes the first filter you specify.
Build.VERSION.SDK_INT >= 23 -> "*/*"
else -> mimeTypes.joinToString(" ")
}
return Intent.createChooser(intent, caption)
}
data class GetContentResultEntry(
val uri : Uri,
val mimeType : String? = null,
var time : Long? = null
)
// returns list of pair of uri and mime-type.
fun Intent.handleGetContentResult(contentResolver : ContentResolver) : ArrayList<GetContentResultEntry> {
val urlList = ArrayList<GetContentResultEntry>()
// 単一選択
this.data?.let {
urlList.add(GetContentResultEntry(it, this.type))
}
// 複数選択
val cd = this.clipData
if(cd != null) {
for(i in 0 until cd.itemCount) {
cd.getItemAt(i)?.uri?.let { uri ->
if(null == urlList.find { it.uri == uri }) {
urlList.add(GetContentResultEntry(uri))
}
}
}
}
urlList.forEach {
try {
contentResolver.takePersistableUriPermission(
it.uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} catch(_ : Throwable) {
}
}
return urlList
}