Skip to content

Commit ecce011

Browse files
committed
Fix external storage file saving compatibility for Android 9 and earlier versions in sample
1 parent 1b78f8b commit ecce011

File tree

1 file changed

+137
-59
lines changed
  • sample/src/main/java/com/github/squti/androidwaverecordersample

1 file changed

+137
-59
lines changed

sample/src/main/java/com/github/squti/androidwaverecordersample/MainActivity.kt

Lines changed: 137 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525
package com.github.squti.androidwaverecordersample
2626

2727
import android.Manifest
28+
import android.content.ContentUris
2829
import android.content.ContentValues
2930
import android.content.Intent
3031
import android.content.pm.PackageManager
3132
import android.media.AudioFormat
3233
import android.net.Uri
3334
import android.os.Build
3435
import android.os.Bundle
36+
import android.os.Environment
3537
import android.provider.MediaStore
3638
import android.provider.Settings
3739
import android.util.Log
@@ -44,12 +46,13 @@ import androidx.core.content.ContextCompat
4446
import com.github.squti.androidwaverecorder.RecorderState
4547
import com.github.squti.androidwaverecorder.WaveRecorder
4648
import com.github.squti.androidwaverecordersample.databinding.ActivityMainBinding
47-
import java.io.IOException
49+
import java.io.File
4850
import java.util.Locale
4951
import java.util.concurrent.TimeUnit
5052

5153
class MainActivity : AppCompatActivity() {
5254
private val PERMISSIONS_REQUEST_RECORD_AUDIO = 77
55+
private val PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 88
5356

5457
private lateinit var waveRecorder: WaveRecorder
5558
private lateinit var filePath: String
@@ -65,39 +68,70 @@ class MainActivity : AppCompatActivity() {
6568
initRecorder(isSaveToExternalStorage = false)
6669

6770
binding.saveToExternalStorageSwitch.setOnCheckedChangeListener { _, isChecked ->
68-
if (isChecked) {
71+
if (!isChecked) {
72+
resetSwitches()
73+
initRecorder(isSaveToExternalStorage = false)
74+
return@setOnCheckedChangeListener
75+
}
76+
77+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
78+
resetSwitches()
79+
initRecorder(isSaveToExternalStorage = true)
80+
return@setOnCheckedChangeListener
81+
}
82+
83+
if (ContextCompat.checkSelfPermission(
84+
this,
85+
Manifest.permission.WRITE_EXTERNAL_STORAGE
86+
) == PackageManager.PERMISSION_GRANTED
87+
) {
88+
resetSwitches()
6989
initRecorder(isSaveToExternalStorage = true)
90+
return@setOnCheckedChangeListener
91+
}
92+
93+
if (ActivityCompat.shouldShowRequestPermissionRationale(
94+
this,
95+
Manifest.permission.WRITE_EXTERNAL_STORAGE
96+
)
97+
) {
98+
showPermissionSettingsDialog()
7099
} else {
71-
initRecorder(isSaveToExternalStorage = false)
100+
ActivityCompat.requestPermissions(
101+
this,
102+
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
103+
PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
104+
)
72105
}
73106
}
74107

75108
binding.startStopRecordingButton.setOnClickListener {
109+
if (isRecording) {
110+
waveRecorder.stopRecording()
111+
return@setOnClickListener
112+
}
76113

77-
if (!isRecording) {
78-
if (ContextCompat.checkSelfPermission(
79-
this,
80-
Manifest.permission.RECORD_AUDIO
81-
) != PackageManager.PERMISSION_GRANTED
82-
) {
83-
if (ActivityCompat.shouldShowRequestPermissionRationale(
84-
this,
85-
Manifest.permission.RECORD_AUDIO
86-
)
87-
) {
88-
ActivityCompat.requestPermissions(
89-
this,
90-
arrayOf(Manifest.permission.RECORD_AUDIO),
91-
PERMISSIONS_REQUEST_RECORD_AUDIO
92-
)
93-
} else {
94-
showPermissionSettingsDialog()
95-
}
96-
} else {
97-
waveRecorder.startRecording()
98-
}
114+
if (ContextCompat.checkSelfPermission(
115+
this,
116+
Manifest.permission.RECORD_AUDIO
117+
) == PackageManager.PERMISSION_GRANTED
118+
) {
119+
waveRecorder.startRecording()
120+
return@setOnClickListener
121+
}
122+
123+
if (ActivityCompat.shouldShowRequestPermissionRationale(
124+
this,
125+
Manifest.permission.RECORD_AUDIO
126+
)
127+
) {
128+
showPermissionSettingsDialog()
99129
} else {
100-
waveRecorder.stopRecording()
130+
ActivityCompat.requestPermissions(
131+
this,
132+
arrayOf(Manifest.permission.RECORD_AUDIO),
133+
PERMISSIONS_REQUEST_RECORD_AUDIO
134+
)
101135
}
102136
}
103137

@@ -109,34 +143,47 @@ class MainActivity : AppCompatActivity() {
109143
}
110144
}
111145
binding.showAmplitudeSwitch.setOnCheckedChangeListener { _, isChecked ->
112-
if (isChecked) {
113-
binding.amplitudeTextView.text = "Amplitude : 0"
114-
binding.amplitudeTextView.visibility = View.VISIBLE
115-
waveRecorder.onAmplitudeListener = {
116-
binding.amplitudeTextView.text = "Amplitude : $it"
117-
}
146+
if (this::waveRecorder.isInitialized) {
147+
if (isChecked) {
148+
binding.amplitudeTextView.text = "Amplitude : 0"
149+
binding.amplitudeTextView.visibility = View.VISIBLE
150+
waveRecorder.onAmplitudeListener = {
151+
binding.amplitudeTextView.text = "Amplitude : $it"
152+
}
118153

119-
} else {
120-
waveRecorder.onAmplitudeListener = null
121-
binding.amplitudeTextView.visibility = View.GONE
154+
} else {
155+
waveRecorder.onAmplitudeListener = null
156+
binding.amplitudeTextView.visibility = View.GONE
157+
}
122158
}
123159
}
124160

125161
binding.silenceDetectionSwitch.setOnCheckedChangeListener { _, isChecked ->
126-
waveRecorder.silenceDetection = isChecked
127-
if (isChecked)
128-
Toast.makeText(this, "Noise Suppressor Activated", Toast.LENGTH_SHORT).show()
129-
162+
if (this::waveRecorder.isInitialized) {
163+
waveRecorder.silenceDetection = isChecked
164+
if (isChecked)
165+
Toast.makeText(this, "Silence Detection Activated", Toast.LENGTH_SHORT).show()
166+
}
130167
}
131168

132169
binding.noiseSuppressorSwitch.setOnCheckedChangeListener { _, isChecked ->
133-
waveRecorder.noiseSuppressorActive = isChecked
134-
if (isChecked)
135-
Toast.makeText(this, "Noise Suppressor Activated", Toast.LENGTH_SHORT).show()
170+
if (this::waveRecorder.isInitialized) {
171+
waveRecorder.noiseSuppressorActive = isChecked
172+
173+
if (isChecked) {
174+
Toast.makeText(this, "Noise Suppressor Activated", Toast.LENGTH_SHORT).show()
175+
}
176+
}
136177

137178
}
138179
}
139180

181+
private fun resetSwitches() {
182+
binding.showAmplitudeSwitch.isChecked = false
183+
binding.silenceDetectionSwitch.isChecked = false
184+
binding.noiseSuppressorSwitch.isChecked = false
185+
}
186+
140187
private fun initRecorder(isSaveToExternalStorage: Boolean) {
141188
if (isSaveToExternalStorage)
142189
initWithExternalStorage("audioFile")
@@ -191,9 +238,9 @@ class MainActivity : AppCompatActivity() {
191238
binding.recordingTextView.visibility = View.GONE
192239
binding.messageTextView.visibility = View.VISIBLE
193240
binding.pauseResumeRecordingButton.visibility = View.GONE
194-
binding.showAmplitudeSwitch.isChecked = false
195241
binding.startStopRecordingButton.text = "START"
196242
binding.noiseSuppressorSwitch.isEnabled = true
243+
resetSwitches()
197244
Toast.makeText(this, "File saved at : $filePath", Toast.LENGTH_LONG).show()
198245
}
199246

@@ -213,6 +260,10 @@ class MainActivity : AppCompatActivity() {
213260
if (requestCode == PERMISSIONS_REQUEST_RECORD_AUDIO && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
214261
waveRecorder.startRecording()
215262
}
263+
if (requestCode == PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
264+
resetSwitches()
265+
initRecorder(isSaveToExternalStorage = true)
266+
}
216267
}
217268

218269
companion object {
@@ -235,35 +286,62 @@ class MainActivity : AppCompatActivity() {
235286
}
236287
}
237288

238-
private fun initWithExternalStorage(fileName: String): Boolean {
289+
private fun initWithExternalStorage(fileName: String) {
239290
val folderName = "Android-Wave-Recorder"
240291
val audioUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
241292
MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
242293
} else MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
243-
294+
val path =
295+
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).absolutePath + "/$folderName/$fileName.wav"
244296
val contentValues = ContentValues().apply {
245297
put(MediaStore.Audio.Media.DISPLAY_NAME, "$fileName.wav")
246298
put(MediaStore.Audio.Media.MIME_TYPE, "audio/x-wav")
247-
put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/$folderName")
299+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
300+
put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/$folderName")
301+
} else {
302+
val file = File(path)
303+
val parentFile = file.parentFile
304+
if (parentFile != null && !parentFile.exists()) {
305+
parentFile.mkdirs()
306+
}
307+
put(MediaStore.Audio.AudioColumns.DATA, path)
308+
}
248309
}
249-
return try {
250-
contentResolver.insert(audioUri, contentValues)?.also { uri ->
251-
waveRecorder = WaveRecorder(uri, context = this)
310+
311+
try {
312+
val existingUri = contentResolver.query(
313+
audioUri,
314+
arrayOf(MediaStore.Audio.Media._ID),
315+
"${MediaStore.Audio.AudioColumns.DATA}=?",
316+
arrayOf(path),
317+
null
318+
)?.use { cursor ->
319+
if (cursor.moveToFirst()) {
320+
ContentUris.withAppendedId(
321+
audioUri,
322+
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID))
323+
)
324+
} else {
325+
null
326+
}
327+
}
328+
329+
val uri = existingUri ?: contentResolver.insert(audioUri, contentValues)
330+
uri?.let {
331+
waveRecorder = WaveRecorder(it, context = this)
252332
.configureWaveSettings {
253333
sampleRate = 44100
254-
channels = AudioFormat.CHANNEL_IN_STEREO
255-
audioEncoding = AudioFormat.ENCODING_PCM_32BIT
334+
channels = AudioFormat.CHANNEL_IN_MONO
335+
audioEncoding = AudioFormat.ENCODING_PCM_FLOAT
256336
}.configureSilenceDetection {
257-
minAmplitudeThreshold = 80
337+
minAmplitudeThreshold = 2000
258338
bufferDurationInMillis = 1500
259339
preSilenceDurationInMillis = 1500
260340
}
261341
filePath = "/Music/$folderName/$fileName.wav"
262-
} ?: throw IOException("Couldn't create MediaStore entry")
263-
true
264-
} catch (e: IOException) {
342+
}
343+
} catch (e: Exception) {
265344
e.printStackTrace()
266-
false
267345
}
268346
}
269347

@@ -274,10 +352,10 @@ class MainActivity : AppCompatActivity() {
274352
waveRecorder = WaveRecorder(filePath)
275353
.configureWaveSettings {
276354
sampleRate = 44100
277-
channels = AudioFormat.CHANNEL_IN_STEREO
278-
audioEncoding = AudioFormat.ENCODING_PCM_32BIT
355+
channels = AudioFormat.CHANNEL_IN_MONO
356+
audioEncoding = AudioFormat.ENCODING_PCM_FLOAT
279357
}.configureSilenceDetection {
280-
minAmplitudeThreshold = 80
358+
minAmplitudeThreshold = 2000
281359
bufferDurationInMillis = 1500
282360
preSilenceDurationInMillis = 1500
283361
}

0 commit comments

Comments
 (0)