add aac,3gp,m4a audio format in media attachment
This commit is contained in:
parent
5c72dc52e5
commit
d97dc031df
|
@ -34,6 +34,7 @@
|
|||
<w>flac</w>
|
||||
<w>flexbox</w>
|
||||
<w>foregrounder</w>
|
||||
<w>ftyp</w>
|
||||
<w>gifv</w>
|
||||
<w>github</w>
|
||||
<w>gmail</w>
|
||||
|
@ -45,6 +46,7 @@
|
|||
<w>idat</w>
|
||||
<w>idempotency</w>
|
||||
<w>ihdr</w>
|
||||
<w>kddi</w>
|
||||
<w>kenglxn</w>
|
||||
<w>kotlinx</w>
|
||||
<w>mailto</w>
|
||||
|
|
|
@ -135,6 +135,18 @@
|
|||
<data android:mimeType="video/*"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="audio/*"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="audio/*"/>
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
|
|
|
@ -54,7 +54,7 @@ class ActCallback : AppCompatActivity() {
|
|||
// ACTION_SEND か ACTION_SEND_MULTIPLE
|
||||
Intent.ACTION_SEND == action
|
||||
|| Intent.ACTION_SEND_MULTIPLE == action
|
||||
// ACTION_VIEW かつ type が 画像かビデオ
|
||||
// ACTION_VIEW かつ type が 画像かビデオか音声
|
||||
|| Intent.ACTION_VIEW == action && type.isMediaMimeType() ) {
|
||||
|
||||
// Google Photo などから送られるIntentに含まれるuriの有効期間はActivityが閉じられるまで
|
||||
|
|
|
@ -92,6 +92,7 @@ class ActPost : AppCompatActivity(),
|
|||
private const val REQUEST_CODE_MUSHROOM = 3
|
||||
private const val REQUEST_CODE_VIDEO = 4
|
||||
private const val REQUEST_CODE_ATTACHMENT_OLD = 5
|
||||
private const val REQUEST_CODE_SOUND = 6
|
||||
|
||||
private const val PERMISSION_REQUEST_CODE = 1
|
||||
|
||||
|
@ -123,6 +124,11 @@ class ActPost : AppCompatActivity(),
|
|||
add("audio/x-pn-wav")
|
||||
add("audio/flac")
|
||||
add("audio/x-flac")
|
||||
|
||||
// https://github.com/tootsuite/mastodon/pull/11342
|
||||
add("audio/aac")
|
||||
add("audio/m4a")
|
||||
add("audio/3gpp")
|
||||
}
|
||||
|
||||
private val imageHeaderList = arrayOf(
|
||||
|
@ -152,6 +158,44 @@ class ActPost : AppCompatActivity(),
|
|||
)
|
||||
)
|
||||
|
||||
private val sig3gp = arrayOf(
|
||||
"3ge6",
|
||||
"3ge7",
|
||||
"3gg6",
|
||||
"3gp1",
|
||||
"3gp2",
|
||||
"3gp3",
|
||||
"3gp4",
|
||||
"3gp5",
|
||||
"3gp6",
|
||||
"3gp7",
|
||||
"3gr6",
|
||||
"3gr7",
|
||||
"3gs6",
|
||||
"3gs7",
|
||||
"kddi"
|
||||
).map { it.toCharArray().toLowerByteArray() }
|
||||
|
||||
private val sigM4a = arrayOf(
|
||||
"M4A ",
|
||||
"M4B ",
|
||||
"M4P "
|
||||
).map { it.toCharArray().toLowerByteArray() }
|
||||
|
||||
private val sigFtyp = "ftyp".toCharArray().toLowerByteArray()
|
||||
|
||||
private fun matchSig(
|
||||
data : ByteArray,
|
||||
dataOffset : Int,
|
||||
sig : ByteArray,
|
||||
sigSize : Int = sig.size
|
||||
) : Boolean {
|
||||
for(i in 0 until sigSize) {
|
||||
if(data[dataOffset + i] != sig[i]) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun findMimeTypeByFileHeader(
|
||||
contentResolver : ContentResolver,
|
||||
uri : Uri
|
||||
|
@ -165,27 +209,60 @@ class ActPost : AppCompatActivity(),
|
|||
val header = pair.second
|
||||
if(nRead >= header.size && data.startWith(header)) return type
|
||||
}
|
||||
// scan mp3 frame header
|
||||
loop@ for(i in 0 until nRead - 4) {
|
||||
|
||||
// scan frame header
|
||||
for(i in 0 until nRead - 8) {
|
||||
|
||||
if(! matchSig(data, i, sigFtyp)) continue
|
||||
|
||||
// 3gpp check
|
||||
for(s in sig3gp) {
|
||||
if(matchSig(data, i + 4, s)) return "audio/3gpp"
|
||||
}
|
||||
|
||||
// m4a check
|
||||
for(s in sigM4a) {
|
||||
if(matchSig(data, i + 4, s)) return "audio/m4a"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// scan frame header
|
||||
loop@ for(i in 0 until nRead - 2) {
|
||||
|
||||
// mpeg frame header
|
||||
val b0 = data[i].toInt() and 255
|
||||
if(b0 != 255) continue
|
||||
val b1 = data[i + 1].toInt() and 255
|
||||
if((b1 and 0b11100000) != 0b11100000) continue
|
||||
|
||||
// mpegVersionId
|
||||
when(((b1 shr 3) and 3)) {
|
||||
1 -> continue@loop
|
||||
}
|
||||
val mpegVersionId = ((b1 shr 3) and 3)
|
||||
// 00 mpeg 2.5
|
||||
// 01 not used
|
||||
// 10 (mp3) mpeg 2 / (AAC) mpeg-4
|
||||
// 11 (mp3) mpeg 1 / (AAC) mpeg-2
|
||||
|
||||
// mpegLayerId
|
||||
when(((b1 shr 1) and 3)) {
|
||||
1 -> {
|
||||
}
|
||||
@Suppress("MoveVariableDeclarationIntoWhen")
|
||||
val mpegLayerId = ((b1 shr 1) and 3)
|
||||
// 00 (mp3)not used / (AAC) always 0
|
||||
// 01 (mp3)layer III
|
||||
// 10 (mp3)layer II
|
||||
// 11 (mp3)layer I
|
||||
|
||||
else -> continue@loop
|
||||
}
|
||||
when(mpegLayerId) {
|
||||
0 -> when(mpegVersionId) {
|
||||
2, 3 -> return "audio/aac"
|
||||
|
||||
return "audio/mp3"
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
1 -> when(mpegVersionId) {
|
||||
0, 2, 3 -> return "audio/mp3"
|
||||
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(ex : Throwable) {
|
||||
|
@ -193,16 +270,6 @@ class ActPost : AppCompatActivity(),
|
|||
}
|
||||
return null
|
||||
}
|
||||
// private void performCameraVideo(){
|
||||
//
|
||||
// try{
|
||||
// Intent takeVideoIntent = new Intent( MediaStore.ACTION_VIDEO_CAPTURE );
|
||||
// startActivityForResult( takeVideoIntent, REQUEST_CODE_VIDEO );
|
||||
// }catch( Throwable ex ){
|
||||
// warning.trace( ex );
|
||||
// Utils.showToast( this, ex, "opening video app failed." );
|
||||
// }
|
||||
// }
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
|
@ -422,22 +489,31 @@ class ActPost : AppCompatActivity(),
|
|||
}
|
||||
|
||||
override fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent?) {
|
||||
|
||||
if(requestCode == REQUEST_CODE_ATTACHMENT_OLD && resultCode == Activity.RESULT_OK) {
|
||||
checkAttachments(data?.handleGetContentResult(contentResolver))
|
||||
|
||||
} else if(requestCode == REQUEST_CODE_ATTACHMENT && resultCode == Activity.RESULT_OK) {
|
||||
checkAttachments(data?.handleGetContentResult(contentResolver))
|
||||
} else if(requestCode == REQUEST_CODE_CAMERA) {
|
||||
|
||||
if(resultCode != Activity.RESULT_OK) {
|
||||
if(resultCode != RESULT_OK) {
|
||||
when(requestCode) {
|
||||
REQUEST_CODE_CAMERA -> {
|
||||
// 失敗したら DBからデータを削除
|
||||
val uriCameraImage = this.uriCameraImage
|
||||
if(uriCameraImage != null) {
|
||||
contentResolver.delete(uriCameraImage, null, null)
|
||||
this@ActPost.uriCameraImage = null
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when(requestCode) {
|
||||
REQUEST_CODE_ATTACHMENT_OLD -> checkAttachments(
|
||||
data?.handleGetContentResult(
|
||||
contentResolver
|
||||
)
|
||||
)
|
||||
REQUEST_CODE_ATTACHMENT -> checkAttachments(
|
||||
data?.handleGetContentResult(
|
||||
contentResolver
|
||||
)
|
||||
)
|
||||
|
||||
REQUEST_CODE_CAMERA -> {
|
||||
// 画像のURL
|
||||
val uri = data?.data ?: uriCameraImage
|
||||
if(uri != null) {
|
||||
|
@ -446,12 +522,15 @@ class ActPost : AppCompatActivity(),
|
|||
showToast(this@ActPost, false, "missing image uri")
|
||||
}
|
||||
}
|
||||
} else if(requestCode == REQUEST_CODE_VIDEO && resultCode == Activity.RESULT_OK) {
|
||||
data?.data?.let { addAttachment(it) }
|
||||
|
||||
} else if(requestCode == REQUEST_CODE_MUSHROOM && resultCode == Activity.RESULT_OK) {
|
||||
REQUEST_CODE_VIDEO, REQUEST_CODE_SOUND -> data?.data?.let { addAttachment(it) }
|
||||
|
||||
REQUEST_CODE_MUSHROOM -> {
|
||||
data?.getStringExtra("replace_key")?.let { applyMushroomResult(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
|
@ -1654,9 +1733,6 @@ class ActPost : AppCompatActivity(),
|
|||
// }
|
||||
|
||||
val a = ActionsDialog()
|
||||
a.addAction(getString(R.string.image_capture)) {
|
||||
performCamera()
|
||||
}
|
||||
a.addAction(getString(R.string.pick_images)) {
|
||||
openAttachmentChooser(R.string.pick_images, "image/*", "video/*")
|
||||
}
|
||||
|
@ -1666,12 +1742,24 @@ class ActPost : AppCompatActivity(),
|
|||
a.addAction(getString(R.string.pick_audios)) {
|
||||
openAttachmentChooser(R.string.pick_audios, "audio/*")
|
||||
}
|
||||
a.addAction(getString(R.string.image_capture)) {
|
||||
performCamera()
|
||||
}
|
||||
a.addAction(getString(R.string.video_capture)) {
|
||||
performCapture(
|
||||
REQUEST_CODE_VIDEO,
|
||||
MediaStore.ACTION_VIDEO_CAPTURE,
|
||||
"can't open video capture app."
|
||||
)
|
||||
}
|
||||
a.addAction(getString(R.string.voice_capture)) {
|
||||
performCapture(
|
||||
REQUEST_CODE_SOUND,
|
||||
MediaStore.Audio.Media.RECORD_SOUND_ACTION,
|
||||
"can't open voice capture app."
|
||||
)
|
||||
}
|
||||
|
||||
// a.addAction( getString( R.string.video_capture ), new Runnable() {
|
||||
// @Override public void run(){
|
||||
// performCameraVideo();
|
||||
// }
|
||||
// } );
|
||||
a.show(this, null)
|
||||
|
||||
}
|
||||
|
@ -2144,9 +2232,7 @@ class ActPost : AppCompatActivity(),
|
|||
}
|
||||
|
||||
private fun performCamera() {
|
||||
|
||||
try {
|
||||
// カメラで撮影
|
||||
val filename = System.currentTimeMillis().toString() + ".jpg"
|
||||
val values = ContentValues()
|
||||
values.put(MediaStore.Images.Media.TITLE, filename)
|
||||
|
@ -2165,14 +2251,20 @@ class ActPost : AppCompatActivity(),
|
|||
|
||||
}
|
||||
|
||||
private fun performCapture(requestCode : Int, action : String, errorCaption : String) {
|
||||
try {
|
||||
startActivityForResult(Intent(action), requestCode)
|
||||
} catch(ex : Throwable) {
|
||||
log.trace(ex);
|
||||
showToast(this, ex, errorCaption)
|
||||
}
|
||||
}
|
||||
|
||||
private fun preparePermission() {
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
// No explanation needed, we can request the permission.
|
||||
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) // Manifest.permission.CAMERA,
|
||||
,
|
||||
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||
PERMISSION_REQUEST_CODE
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -31,3 +31,4 @@
|
|||
<string name="more">עוד</string>
|
||||
<string name="close_column">סגור את העמודה</string>
|
||||
</resources>
|
||||
|
||||
|
|
|
@ -349,6 +349,8 @@
|
|||
<string name="image">画像</string>
|
||||
<string name="image_alpha">画像の不透明度</string>
|
||||
<string name="image_capture">カメラで撮影</string>
|
||||
<string name="video_capture">動画を記録</string>
|
||||
<string name="voice_capture">音声を記録</string>
|
||||
<string name="in_reply_to_id_conversion_failed">アカウント切り替えできません。in_reply_toのID変換に失敗しました。</string>
|
||||
<string name="input_access_token">アクセストークン</string>
|
||||
<string name="input_access_token_desc">通常のユーザ認証の代わりにアクセストークンを指定します。(上級者向け)</string>
|
||||
|
@ -737,7 +739,6 @@
|
|||
<string name="version_is">バージョン %1$s</string>
|
||||
<string name="vibration">振動</string>
|
||||
<string name="video_buffering">バッファ中…</string>
|
||||
<string name="video_capture">動画の撮影</string>
|
||||
<string name="video_pick">動画の選択</string>
|
||||
<string name="visibility">公開範囲</string>
|
||||
<string name="visibility_direct">ダイレクト</string>
|
||||
|
|
|
@ -232,6 +232,8 @@
|
|||
<string name="dont_resize">Don\'t resize</string>
|
||||
<string name="long_side_pixel">Resize to %1$d pixels</string>
|
||||
<string name="image_capture">Take a picture</string>
|
||||
<string name="video_capture">Capture a video</string>
|
||||
<string name="voice_capture">Capture a voice</string>
|
||||
<string name="missing_permission_to_access_media">Missing app permission to access media.</string>
|
||||
<string name="attachment_uploading">Uploading media attachment…</string>
|
||||
<string name="attachment_uploaded">Media attachment was uploaded.</string>
|
||||
|
@ -492,7 +494,6 @@
|
|||
<string name="quote_all_hashtag_of">Quote all hashtags \"%1$s\"</string>
|
||||
<string name="parsing_response">Parsing response…</string>
|
||||
<string name="video_pick">Pick video</string>
|
||||
<string name="video_capture">Capture video</string>
|
||||
<string name="already_followed">Already followed.</string>
|
||||
<string name="cant_get_web_setting_visibility">Can\'t get visibility setting in web app.</string>
|
||||
<string name="mastodon_1_6_later">Mastodon 1.6 or later</string>
|
||||
|
|
Loading…
Reference in New Issue