From 278e631b6d3deb8582aa2a5d4172259e498ee788 Mon Sep 17 00:00:00 2001 From: SheTieJun <375105540@qq.com> Date: Thu, 21 Mar 2024 16:52:04 +0800 Subject: [PATCH] =?UTF-8?q?:white=5Fcheck=5Fmark:=20=E6=9B=B4=E6=96=B0demo?= =?UTF-8?q?=20=E5=85=BC=E5=AE=B934?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 +- app/src/main/AndroidManifest.xml | 13 +- .../java/me/shetj/mp3recorder/MainActivity.kt | 34 +---- .../record/activity/mix/RecordActivity.kt | 7 +- .../record/activity/mix/RecordPage.kt | 35 ++--- .../record/utils/LocalMusicQUtils.kt | 133 ++++++++++++------ .../mp3recorder/record/utils/RecordUtils.kt | 48 +++---- .../bg_record_pop_content.9.png | Bin 0 -> 5899 bytes .../main/res/drawable/bg_circle_record.xml | 2 +- .../main/res/layout/activity_main_test.xml | 8 -- .../main/res/layout/activity_my_record.xml | 4 +- app/src/main/res/values/styles.xml | 2 +- settings.gradle.kts | 1 - 13 files changed, 142 insertions(+), 148 deletions(-) create mode 100644 app/src/main/res/drawable-xxhdpi/bg_record_pop_content.9.png diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 181e99c..c12ebf5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,6 +10,7 @@ plugins { androidApplication("me.shetj.mp3recorder"){ defaultConfig { + minSdk = 24 ndk { this.abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86_64", "x86")) } @@ -37,9 +38,7 @@ dependencies { implementation(project(":recorder-mix")) implementation(project(":recorder-sim")) implementation(project(":recorder-core")) - implementation(project(":recorder-ui")) implementation(project(":recorder-st")) implementation("com.github.SheTieJun:BaseKit:85dc1cb78d") ksp(libs.androidx.room.compiler) - implementation("com.github.SheTieJun:OrangeDialog:0.0.2") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0452cf..f0c2c04 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,8 +3,13 @@ > - - + + + + + @@ -18,7 +23,7 @@ android:requestLegacyExternalStorage="true" android:roundIcon="@mipmap/icon_record_app" android:supportsRtl="true" - android:theme="@style/BaseTheme.MD3"> + android:theme="@style/AppTheme"> diff --git a/app/src/main/java/me/shetj/mp3recorder/MainActivity.kt b/app/src/main/java/me/shetj/mp3recorder/MainActivity.kt index 788151a..9ea9563 100644 --- a/app/src/main/java/me/shetj/mp3recorder/MainActivity.kt +++ b/app/src/main/java/me/shetj/mp3recorder/MainActivity.kt @@ -1,7 +1,6 @@ package me.shetj.mp3recorder -import android.Manifest import android.animation.ObjectAnimator import android.content.Context import android.graphics.Color @@ -14,19 +13,16 @@ import androidx.core.animation.doOnEnd import androidx.core.splashscreen.SplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.NonCancellable.start import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.shetj.base.BaseKit -import me.shetj.base.ktx.hasPermission +import me.shetj.base.fix.FixPermission import me.shetj.base.ktx.setAppearance -import me.shetj.base.ktx.showToast import me.shetj.base.ktx.start import me.shetj.base.mvvm.viewbind.BaseBindingActivity import me.shetj.base.mvvm.viewbind.BaseViewModel import me.shetj.mp3recorder.databinding.ActivityMainTestBinding import me.shetj.mp3recorder.record.activity.mix.RecordActivity -import me.shetj.recorder.ui.RecorderPopup class MainActivity : BaseBindingActivity() { private var splashScreen: SplashScreen? =null @@ -60,34 +56,14 @@ class MainActivity : BaseBindingActivity super.onCreate(savedInstanceState) } - private val recorderPopup: RecorderPopup by lazy { - RecorderPopup(this, needPlay = false, maxTime = (10 * 1000).toLong()) { - it.showToast() - } - } - override fun initBaseView() { - hasPermission( - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.RECORD_AUDIO, - isRequest = true - ) mBinding.btnDemo3.setOnClickListener { - if (hasPermission( - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.RECORD_AUDIO, isRequest = true - ) - ) { + if (FixPermission.checkReadMediaFile(this, isRequest = true)) { start() } } - mBinding.btnDemo4.setOnClickListener { - recorderPopup.showPop() - } mBinding.msg.apply { append("获取当前手机录音最佳参数:") append("最佳采样率:${getBestSampleRate()}\n") @@ -129,10 +105,4 @@ class MainActivity : BaseBindingActivity super.onRequestPermissionsResult(requestCode, permissions, grantResults) } - - override fun onBackPressed() { - if (recorderPopup.onBackPress()) { - super.onBackPressed() - } - } } diff --git a/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordActivity.kt b/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordActivity.kt index c9b06b5..ebecba8 100644 --- a/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordActivity.kt +++ b/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordActivity.kt @@ -17,6 +17,7 @@ import me.shetj.mp3recorder.R import me.shetj.mp3recorder.record.RecordingNotification import me.shetj.mp3recorder.record.utils.EventCallback import kotlinx.coroutines.delay +import me.shetj.base.fix.FixPermission import me.shetj.base.ktx.launch @@ -96,11 +97,7 @@ class RecordActivity : BaseActivity(), EventCallback { } private fun canRecord() { - hasPermission( - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.RECORD_AUDIO, isRequest = true - ) + FixPermission.checkReadMediaFile(this,true) } override fun onBackPressed() { diff --git a/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordPage.kt b/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordPage.kt index 81a33bd..8929d21 100644 --- a/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordPage.kt +++ b/app/src/main/java/me/shetj/mp3recorder/record/activity/mix/RecordPage.kt @@ -15,6 +15,7 @@ import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.AppCompatButton import androidx.lifecycle.lifecycleScope +import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow @@ -22,7 +23,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import me.shetj.base.ktx.logI import me.shetj.base.tools.app.ArmsUtils -import me.shetj.dialog.OrangeDialog import me.shetj.mp3recorder.R import me.shetj.mp3recorder.databinding.PageRecordMixBinding import me.shetj.mp3recorder.record.bean.MusicQ @@ -195,10 +195,6 @@ open class RecordPage( } - override fun onReset() { - super.onReset() - } - override fun needPermission() { callback.onEvent(3) } @@ -245,13 +241,13 @@ open class RecordPage( * 是否录制新内容 */ private fun showRecordNewDialog() { - OrangeDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setTitle("录音已保存") - .setContent("录音已保存。是否继续录制下一条?") - .setNegativeText("查看本条") - .setOnNegativeCallBack { _, _ -> callback.onEvent(1) } - .setPositiveText("录下一条") - .setonPositiveCallBack { _, _ -> + .setMessage("录音已保存。是否继续录制下一条?") + .setNegativeButton("查看本条"){ + _, _ -> callback.onEvent(1) + } + .setPositiveButton("录下一条"){ _, _ -> setRecord(null) ArmsUtils.makeText("上条录音已保存至“我的录音”") } @@ -326,18 +322,17 @@ open class RecordPage( * 展示重新录制 */ private fun showRerecordDialog() { - OrangeDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setTitle("重新录制") - .setContent("确定删除当前的录音,并重新录制吗?") - .setNegativeText("取消").setOnNegativeCallBack { _, _ -> recordUtils!!.stopFullRecord() } - .setPositiveText("重录").setonPositiveCallBack { _, _ -> + .setMessage("确定删除当前的录音,并重新录制吗?") + .setNegativeButton("取消") { _, _ -> recordUtils!!.stopFullRecord() } + .setPositiveButton("重录") { _, _ -> //可自行判断是否删除老的文件 oldRecord?.audioLength = 0 oldRecord?.audio_url = "" setRecord(oldRecord) recordUtils!!.reset() recordUtils!!.setTime(0) - } .show() } @@ -347,11 +342,11 @@ open class RecordPage( */ private fun showTipDialog() { onPause()//先暂停 - OrangeDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setTitle("温馨提示") - .setContent("确定要停止录音吗?") - .setNegativeText("停止录音").setOnNegativeCallBack { _, _ -> recordUtils!!.stopFullRecord() } - .setPositiveText("继续录音").setonPositiveCallBack { _, _ -> recordUtils!!.startOrPause() } + .setMessage("确定要停止录音吗?") + .setNegativeButton("停止录音") { _, _ -> recordUtils!!.stopFullRecord() } + .setPositiveButton("继续录音") { _, _ -> recordUtils!!.startOrPause() } .show() } diff --git a/app/src/main/java/me/shetj/mp3recorder/record/utils/LocalMusicQUtils.kt b/app/src/main/java/me/shetj/mp3recorder/record/utils/LocalMusicQUtils.kt index c9f2c6e..a194c56 100644 --- a/app/src/main/java/me/shetj/mp3recorder/record/utils/LocalMusicQUtils.kt +++ b/app/src/main/java/me/shetj/mp3recorder/record/utils/LocalMusicQUtils.kt @@ -1,16 +1,20 @@ - package me.shetj.mp3recorder.record.utils import android.annotation.SuppressLint +import android.content.ContentResolver import android.content.ContentUris import android.content.Context +import android.database.Cursor import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.CancellationSignal import android.provider.MediaStore -import me.shetj.mp3recorder.record.bean.MusicQ -import java.util.* -import java.util.concurrent.TimeUnit +import androidx.annotation.RequiresApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import me.shetj.mp3recorder.record.bean.MusicQ +import java.util.* /** @@ -24,60 +28,103 @@ object LocalMusicQUtils { @SuppressLint("Range") @JvmStatic fun loadFileData(context: Context): Flow> { - return flow{ - val resolver = context.contentResolver + return flow { val projection = arrayOf( MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DURATION, - MediaStore.Audio.Media.SIZE - ) - -// Show only videos that are at least 5 minutes in duration. - val selection = "${MediaStore.Video.Media.DURATION} >= ?" - val selectionArgs = arrayOf( - TimeUnit.MILLISECONDS.convert(2, TimeUnit.MINUTES).toString() + MediaStore.Audio.Media.SIZE, + MediaStore.Audio.Media.ALBUM, + MediaStore.Audio.Media.DATE_ADDED, + MediaStore.Audio.Media.ARTIST ) - -// Display videos in alphabetical order based on their display name. - val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" - - val cursor = context.contentResolver.query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - null, - null, - null, - null - )!! - val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID) val musicList = ArrayList() - if (cursor.moveToFirst()) { - do { - val title = - cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)) -// val size = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE)) -// val url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)) - val id = cursor.getLong(idColumn) - val contentUri: Uri = ContentUris.withAppendedId( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id - ) - val duration = - cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION)) - val album = - cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)) - if (duration in 60000..2000000) { + createCursor( + contentResolver = context.contentResolver, + collection = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + projection = projection, + orderBy = MediaStore.Images.Media.DATE_ADDED, + orderAscending = false, + limit = 1000, + offset = 0 + )?.use { cursor -> + val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID) + if (cursor.moveToFirst()) { + do { + val title = + cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)) + val id = cursor.getLong(idColumn) + val contentUri: Uri = ContentUris.withAppendedId( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id + ) + val duration = + cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION)) + val album = + cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)) val music = MusicQ() music.name = title music.url = contentUri music.duration = duration music.imgUrl = album musicList.add(music) - } - } while (cursor.moveToNext()) + } while (cursor.moveToNext()) + } } - cursor.close() emit(musicList) } + } + + + + + private fun createCursor( + contentResolver: ContentResolver, + collection: Uri, + projection: Array, + orderBy: String, + orderAscending: Boolean, + limit: Int = 20, + offset: Int = 0 + ): Cursor? = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> { + val selection = createSelectionBundle(orderBy, orderAscending, limit, offset) + contentResolver.query(collection, projection, selection, CancellationSignal()) + } + + else -> { + val orderDirection = if (orderAscending) "ASC" else "DESC" + var order = when (orderBy) { + "ALPHABET" -> "${MediaStore.Audio.Media.TITLE}, ${MediaStore.Audio.Media.ARTIST} $orderDirection" + else -> "${MediaStore.Audio.Media.DATE_ADDED} $orderDirection" + } + order += " LIMIT $limit OFFSET $offset" + contentResolver.query(collection, projection, null, null, order) + } + } + + @RequiresApi(Build.VERSION_CODES.O) + fun createSelectionBundle( + orderBy: String, + orderAscending: Boolean, + limit: Int = 20, + offset: Int = 0 + ): Bundle = Bundle().apply { + putInt(ContentResolver.QUERY_ARG_LIMIT, limit) + putInt(ContentResolver.QUERY_ARG_OFFSET, offset) + when (orderBy) { + "ALPHABET" -> putStringArray( + ContentResolver.QUERY_ARG_SORT_COLUMNS, + arrayOf(MediaStore.Files.FileColumns.TITLE) + ) + else -> putStringArray( + ContentResolver.QUERY_ARG_SORT_COLUMNS, + arrayOf(MediaStore.Files.FileColumns.DATE_ADDED) + ) + } + val orderDirection = + if (orderAscending) ContentResolver.QUERY_SORT_DIRECTION_ASCENDING else ContentResolver.QUERY_SORT_DIRECTION_DESCENDING + putInt(ContentResolver.QUERY_ARG_SORT_DIRECTION, orderDirection) } + } \ No newline at end of file diff --git a/app/src/main/java/me/shetj/mp3recorder/record/utils/RecordUtils.kt b/app/src/main/java/me/shetj/mp3recorder/record/utils/RecordUtils.kt index 9413ccf..7a9e07e 100644 --- a/app/src/main/java/me/shetj/mp3recorder/record/utils/RecordUtils.kt +++ b/app/src/main/java/me/shetj/mp3recorder/record/utils/RecordUtils.kt @@ -1,4 +1,3 @@ - package me.shetj.mp3recorder.record.utils import android.content.Context @@ -11,13 +10,12 @@ import android.view.View import android.widget.Toast import androidx.core.content.ContextCompat.getSystemService import androidx.lifecycle.MutableLiveData +import com.google.android.material.dialog.MaterialAlertDialogBuilder import me.shetj.base.BaseKit +import me.shetj.base.ktx.logD import me.shetj.base.ktx.logI import me.shetj.base.tools.app.Utils import me.shetj.base.tools.file.EnvironmentStorage -import me.shetj.dialog.OrangeDialog -import me.shetj.dialog.SingleChoiceCallback -import me.shetj.dialog.orangeSingeDialog import me.shetj.mp3recorder.record.RecordingNotification import me.shetj.ndk.lame.LameUtils import me.shetj.player.PlayerListener @@ -34,7 +32,7 @@ import kotlin.math.sqrt */ class RecordUtils( private val callBack: SimRecordListener? -) : RecordListener, PermissionListener,PCMListener { +) : RecordListener, PermissionListener, PCMListener { private var bgmUrl: Uri? = null private var listener: PlayerListener? = null @@ -83,36 +81,27 @@ class RecordUtils( mRecorder?.setOutputFile(saveFile, !TextUtils.isEmpty(file)) mRecorder?.start() } + RecordState.PAUSED -> { mRecorder?.resume() } + RecordState.RECORDING -> { mRecorder?.pause() } + else -> {} } } fun showChangeDialog(context: Context) { - orangeSingeDialog( - context = context, - title = "切换录音工具", - content = "建议不要在录音中进行切换,切换时会自动默认完成", - items = arrayOf("MixRecorder", "SimRecorder", "STRecorder"), - selectIndex = getSelectPosition(recorderType), - singleChoiceCallBack = object : SingleChoiceCallback { - override fun invoke( - dialog: OrangeDialog, - itemView: View, - which: Int, - text: CharSequence? - ): Boolean { - updateRecorderType(which) - dialog.dismiss() - return true - } + MaterialAlertDialogBuilder(context) + .setTitle("切换录音工具") + .setMessage("建议不要在录音中进行切换,切换时会自动默认完成") + .setSingleChoiceItems(arrayOf("MixRecorder", "SimRecorder", "STRecorder"), getSelectPosition(recorderType)) { dialog, which -> + updateRecorderType(which) + dialog.dismiss() } - ) } fun getRecorderTypeName(): String { @@ -173,6 +162,7 @@ class RecordUtils( it.isEnableVBR(false) // 请不要使用,虽然可以正常播放,但是会时间错误获取会错误,暂时没有解决方法 it.setFilter(3000, 200) } + BaseRecorder.RecorderType.SIM -> it.buildSim(Utils.app) BaseRecorder.RecorderType.ST -> it.buildST() } @@ -190,7 +180,7 @@ class RecordUtils( } fun startOrPauseBGM() { - mRecorder?.let { recorder-> + mRecorder?.let { recorder -> if (recorder.isPlayMusic()) { if (recorder.isPauseMusic()) { recorder.resumeMusic() @@ -226,7 +216,7 @@ class RecordUtils( */ fun setTime(startTime: Long) { mRecorder?.setCurDuration(startTime) - callBack?.onRecording(startTime , -1) + callBack?.onRecording(startTime, -1) } /** @@ -271,7 +261,7 @@ class RecordUtils( } override fun onRecording(time: Long, volume: Int) { - callBack?.onRecording((startTime + time) , volume) + callBack?.onRecording((startTime + time), volume) } override fun onPause() { @@ -311,11 +301,11 @@ class RecordUtils( } override fun onBeforePCMToMp3(pcm: ShortArray): ShortArray { - val pcmdb =calculateRealVolume(pcm, pcm.size) - Log.d("onBeforePCMToMp3","修改PCM前DB:$pcmdb" ) + val pcmdb = calculateRealVolume(pcm, pcm.size) + "修改PCM前DB:$pcmdb".logD("onBeforePCMToMp3") val adjustVoice = BytesTransUtil.adjustVoice(pcm, 3) val afterdb = calculateRealVolume(adjustVoice, adjustVoice.size) - Log.d("onBeforePCMToMp3","修改PCM后DB:$afterdb" ) + "修改PCM后DB:$afterdb".logD("onBeforePCMToMp3") return adjustVoice } diff --git a/app/src/main/res/drawable-xxhdpi/bg_record_pop_content.9.png b/app/src/main/res/drawable-xxhdpi/bg_record_pop_content.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3c7b30bafd38ac295b49826ee40947d4f4572405 GIT binary patch literal 5899 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/bg_circle_record.xml b/app/src/main/res/drawable/bg_circle_record.xml index d559469..4be7bd3 100644 --- a/app/src/main/res/drawable/bg_circle_record.xml +++ b/app/src/main/res/drawable/bg_circle_record.xml @@ -2,7 +2,7 @@ - -