Skip to content

Commit

Permalink
implemented recording audio on behalf of other app with intent filter…
Browse files Browse the repository at this point in the history
… & activity result (untested yet)
Leonidius20 committed Aug 8, 2024
1 parent ddcd3d5 commit c58eb15
Showing 7 changed files with 86 additions and 11 deletions.
16 changes: 16 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -41,6 +41,22 @@
</intent-filter>
</activity>

<activity android:name=".ui.RecordDialogActivity"
android:exported="true"
android:label="Record">

<intent-filter>

<action android:name="android.provider.MediaStore.RECORD_SOUND"/>

<!-- needed to receive implicit intents -->
<category android:name="android.intent.category.DEFAULT"/>


</intent-filter>

</activity>

<service
android:name=".data.recorder.RecorderService"
android:exported="false"
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ServiceInfo
import android.media.MediaRecorder
import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.os.ParcelFileDescriptor
@@ -21,6 +22,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import androidx.core.content.IntentCompat
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import com.permissionx.guolindev.PermissionX
@@ -98,13 +100,9 @@ class RecorderService : LifecycleService() {
@Inject
lateinit var settings: Settings

/**
* the launcher class responsible for starting this service.
* injected by RecorderServiceLauncher itself when starting.
* Needed so that we can notify the UI when the service is stopped
* by a broadcast receiver bc of low battery or storage
*/
// var launcher: RecorderServiceLauncher? = null
// needed here so that we can return it from activity started for result (action record audio)
lateinit var fileUri: Uri


override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
@@ -183,7 +181,8 @@ class RecorderService : LifecycleService() {

val fileName = dateFormat.format(Date(System.currentTimeMillis()))

descriptor = getRecFileUri(fileName)
fileUri = getRecFileUri(fileName)
descriptor = applicationContext.contentResolver.openFileDescriptor(fileUri!!, "w")!!

recorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
@@ -263,7 +262,7 @@ class RecorderService : LifecycleService() {
}


private fun getRecFileUri(name: String): ParcelFileDescriptor {
private fun getRecFileUri(name: String): Uri {
val resolver = applicationContext.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
@@ -273,7 +272,7 @@ class RecorderService : LifecycleService() {

val uri = resolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues)

return resolver.openFileDescriptor(uri!!, "w")!!
return uri!!
}

inner class Binder: android.os.Binder() {
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package io.github.leonidius20.recorder.data.recorder

import android.content.ComponentName
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.os.ParcelFileDescriptor
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
@@ -17,6 +21,9 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton

@@ -112,7 +119,6 @@ class RecorderServiceLauncher @Inject constructor(
) {
binder = service as RecorderService.Binder


binder!!.service.lifecycle.addObserver(
serviceLifecycleObserver
)
@@ -156,4 +162,6 @@ class RecorderServiceLauncher @Inject constructor(
_state.value = State.IDLE
}

fun getUri() = binder!!.service.fileUri

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.leonidius20.recorder.ui

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import io.github.leonidius20.recorder.R

/**
* an activity that is launched when some other app requests to record an audio.
* shown as a dialog
*/
@AndroidEntryPoint
class RecordDialogActivity: AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContentView(R.layout.record_dialog)

}

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package io.github.leonidius20.recorder.ui.home

import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
@@ -88,6 +91,16 @@ class HomeFragment : Fragment() {

fun onStopBtnClick() {
viewModel.onStopRecording()

if (requireActivity().intent?.action == MediaStore.Audio.Media.RECORD_SOUND_ACTION) {
// activity was lauched with intent and we need to return the recording
val replyIntent = Intent().apply { setData(viewModel.getUri()) }

requireActivity().run {
setResult(RESULT_OK, replyIntent)
finish()
}
}
}

@RequiresApi(Build.VERSION_CODES.N)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.leonidius20.recorder.ui.home

import android.net.Uri
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
@@ -89,5 +90,6 @@ class HomeViewModel @Inject constructor(
recorderServiceLauncher.stopRecording()
}

fun getUri() = recorderServiceLauncher.getUri()

}
15 changes: 15 additions & 0 deletions app/src/main/res/layout/record_dialog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<fragment
android:id="@+id/nav_host_fragment_activity_record"
android:name="io.github.leonidius20.recorder.ui.home.HomeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"

/>

</FrameLayout>

0 comments on commit c58eb15

Please sign in to comment.