Media Buttons Reciever not working properly in Android Kotlin - android

I have a music service class in my media player app that also shows notifications and handle media buttons from the headphone. But when I enable the next and previous media buttons, It does not respond to the Play Pause button and vice versa. This is my music service code specific to handle media buttons.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val playbackSpeed = if (MusicInterface.isPlaying) 1F else 0F
mediaSession.setMetadata(
MediaMetadataCompat.Builder()
.putLong(
MediaMetadataCompat.METADATA_KEY_DURATION,
mediaPlayer!!.duration.toLong()
)
.build()
)
val playBackState = PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_PLAYING,
mediaPlayer!!.currentPosition.toLong(),
playbackSpeed
)
.setActions(
PlaybackStateCompat.ACTION_SEEK_TO
)
.build()
mediaSession.setPlaybackState(playBackState)
mediaSession.isActive = true
mediaSession.setCallback(object : MediaSessionCompat.Callback() {
override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
val intentAction: String = mediaButtonEvent!!.action!!
if (Intent.ACTION_MEDIA_BUTTON == intentAction) {
val event: KeyEvent =
mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)!!
val keyCode: Int = event.keyCode
if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (MusicInterface.isPlaying) {
//pause music
MusicInterface.binding.interfacePlay.setImageResource(R.drawable.play)
MusicInterface.isPlaying = false
mediaPlayer!!.pause()
showNotification(R.drawable.play_notification)
NowPlaying.binding.fragmentButton.setImageResource(R.drawable.play_now)
} else {
//play music
MusicInterface.binding.interfacePlay.setImageResource(R.drawable.pause)
MusicInterface.isPlaying = true
mediaPlayer!!.start()
showNotification(R.drawable.pause_notification)
NowPlaying.binding.fragmentButton.setImageResource(R.drawable.pause_now)
}
return true
}
if (keyCode == KeyEvent.KEYCODE_MEDIA_NEXT) {
broadcastReceiver.prevNextMusic(increment = true, baseContext)
return true
}
if (keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS) {
broadcastReceiver.prevNextMusic(increment = false, baseContext)
return true
}
}
return false
}
override fun onSeekTo(pos: Long) {
super.onSeekTo(pos)
mediaPlayer!!.seekTo(pos.toInt())
val playBackStateNew = PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_PLAYING,
mediaPlayer!!.currentPosition.toLong(),
playbackSpeed
)
.setActions(PlaybackStateCompat.ACTION_SEEK_TO)
.build()
mediaSession.setPlaybackState(playBackStateNew)
}
})
}
I want to achieve that it responds to all three buttons from the headset(PlayPause, Next, Previous). This is my music service class code.
package com.example.music
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.graphics.BitmapFactory
import android.media.AudioManager
import android.media.MediaPlayer
import android.os.*
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import android.view.KeyEvent
import androidx.core.app.NotificationCompat
class MusicService : Service(), AudioManager.OnAudioFocusChangeListener {
private var myBinder = MyBinder()
var mediaPlayer: MediaPlayer? = null
private lateinit var mediaSession: MediaSessionCompat
private lateinit var runnable: Runnable
lateinit var audioManager: AudioManager
val broadcastReceiver: BroadcastReceiver = BroadcastReceiver()
companion object {
lateinit var playPendingIntent: PendingIntent
}
override fun onBind(intent: Intent?): IBinder {
mediaSession = MediaSessionCompat(baseContext, "Music")
return myBinder
}
inner class MyBinder : Binder() {
fun currentService(): MusicService {
return this#MusicService
}
}
#SuppressLint("UnspecifiedImmutableFlag")
fun showNotification(playPauseButton: Int) {
val intent = Intent(baseContext, MusicInterface::class.java)
intent.putExtra("index", MusicInterface.songPosition)
intent.putExtra("class", "Now Playing Notification")
val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
val contentIntent = PendingIntent.getActivity(this, 0, intent, flag)
val prevIntent =
Intent(baseContext, BroadcastReceiver::class.java).setAction(ApplicationClass.PREVIOUS)
val prevPendingIntent = PendingIntent.getBroadcast(
baseContext, 3, prevIntent, PendingIntent.FLAG_UPDATE_CURRENT
)
val playIntent =
Intent(baseContext, BroadcastReceiver::class.java).setAction(ApplicationClass.PLAY)
playPendingIntent = PendingIntent.getBroadcast(
baseContext, 3, playIntent, PendingIntent.FLAG_UPDATE_CURRENT
)
val nextIntent =
Intent(baseContext, BroadcastReceiver::class.java).setAction(ApplicationClass.NEXT)
val nextPendingIntent = PendingIntent.getBroadcast(
baseContext, 3, nextIntent, PendingIntent.FLAG_UPDATE_CURRENT
)
val exitIntent =
Intent(baseContext, BroadcastReceiver::class.java).setAction(ApplicationClass.EXIT)
val exitPendingIntent = PendingIntent.getBroadcast(
baseContext, 3, exitIntent, PendingIntent.FLAG_UPDATE_CURRENT
)
val imageArt = getImageArt(MusicInterface.musicList[MusicInterface.songPosition].path)
val image = if (imageArt != null) {
BitmapFactory.decodeByteArray(imageArt, 0, imageArt.size)
} else {
BitmapFactory.decodeResource(resources, R.drawable.image_as_cover)
}
val notification = NotificationCompat.Builder(baseContext, ApplicationClass.CHANNEL_ID)
.setContentTitle(MusicInterface.musicList[MusicInterface.songPosition].title)
.setContentText(MusicInterface.musicList[MusicInterface.songPosition].artist)
.setSubText(MusicInterface.musicList[MusicInterface.songPosition].album)
.setSmallIcon(R.drawable.music_note)
.setLargeIcon(image)
.setStyle(
androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.sessionToken)
.setShowActionsInCompactView(0, 1, 2)
).setPriority(NotificationCompat.PRIORITY_HIGH)
.setSilent(true)
.setContentIntent(contentIntent)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC).setOnlyAlertOnce(true)
.addAction(R.drawable.navigate_before_notification, "Previous", prevPendingIntent)
.addAction(playPauseButton, "PlayPause", playPendingIntent)
.addAction(R.drawable.navigate_next_notification, "Next", nextPendingIntent)
.addAction(R.drawable.close_notification, "Exit", exitPendingIntent).build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val playbackSpeed = if (MusicInterface.isPlaying) 1F else 0F
mediaSession.setMetadata(
MediaMetadataCompat.Builder()
.putLong(
MediaMetadataCompat.METADATA_KEY_DURATION,
mediaPlayer!!.duration.toLong()
)
.build()
)
val playBackState = PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_PLAYING,
mediaPlayer!!.currentPosition.toLong(),
playbackSpeed
)
.setActions(
PlaybackStateCompat.ACTION_SEEK_TO
)
.build()
mediaSession.setPlaybackState(playBackState)
mediaSession.isActive = true
mediaSession.setCallback(object : MediaSessionCompat.Callback() {
override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
val intentAction: String = mediaButtonEvent!!.action!!
if (Intent.ACTION_MEDIA_BUTTON == intentAction) {
val event: KeyEvent =
mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)!!
val keyCode: Int = event.keyCode
if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (MusicInterface.isPlaying) {
//pause music
MusicInterface.binding.interfacePlay.setImageResource(R.drawable.play)
MusicInterface.isPlaying = false
mediaPlayer!!.pause()
showNotification(R.drawable.play_notification)
NowPlaying.binding.fragmentButton.setImageResource(R.drawable.play_now)
} else {
//play music
MusicInterface.binding.interfacePlay.setImageResource(R.drawable.pause)
MusicInterface.isPlaying = true
mediaPlayer!!.start()
showNotification(R.drawable.pause_notification)
NowPlaying.binding.fragmentButton.setImageResource(R.drawable.pause_now)
}
return true
}
if (keyCode == KeyEvent.KEYCODE_MEDIA_NEXT) {
broadcastReceiver.prevNextMusic(increment = true, baseContext)
return true
}
if (keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS) {
broadcastReceiver.prevNextMusic(increment = false, baseContext)
return true
}
}
return false
}
override fun onSeekTo(pos: Long) {
super.onSeekTo(pos)
mediaPlayer!!.seekTo(pos.toInt())
val playBackStateNew = PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_PLAYING,
mediaPlayer!!.currentPosition.toLong(),
playbackSpeed
)
.setActions(PlaybackStateCompat.ACTION_SEEK_TO)
.build()
mediaSession.setPlaybackState(playBackStateNew)
}
})
}
startForeground(3, notification)
}
fun initSong() {
try {
if (mediaPlayer == null) mediaPlayer = MediaPlayer()
MusicInterface.musicService!!.mediaPlayer!!.reset()
MusicInterface.musicService!!.mediaPlayer!!.setDataSource(MusicInterface.musicList[MusicInterface.songPosition].path)
MusicInterface.musicService!!.mediaPlayer!!.prepare()
MusicInterface.musicService!!.showNotification(R.drawable.pause_notification)
MusicInterface.binding.interfacePlay.setImageResource((R.drawable.pause))
MusicInterface.binding.interfaceSeekStart.text =
formatDuration(mediaPlayer!!.currentPosition.toLong())
MusicInterface.binding.interfaceSeekEnd.text =
formatDuration(mediaPlayer!!.duration.toLong())
MusicInterface.binding.seekbar.progress = 0
MusicInterface.binding.seekbar.max =
mediaPlayer!!.duration
} catch (e: Exception) {
return
}
}
fun seekBarHandler() {
runnable = Runnable {
MusicInterface.binding.interfaceSeekStart.text =
formatDuration(mediaPlayer!!.currentPosition.toLong())
MusicInterface.binding.seekbar.progress = mediaPlayer!!.currentPosition
Handler(Looper.getMainLooper()).postDelayed(runnable, 200)
}
Handler(Looper.getMainLooper()).postDelayed(runnable, 0)
}
override fun onAudioFocusChange(focusChange: Int) {
if (focusChange <= 0) {
//pause music
MusicInterface.binding.interfacePlay.setImageResource(R.drawable.play)
MusicInterface.isPlaying = false
NowPlaying.binding.fragmentButton.setImageResource(R.drawable.play_now)
mediaPlayer!!.pause()
showNotification(R.drawable.play_notification)
} else {
//play music
MusicInterface.binding.interfacePlay.setImageResource(R.drawable.pause)
MusicInterface.isPlaying = true
mediaPlayer!!.start()
NowPlaying.binding.fragmentButton.setImageResource(R.drawable.pause_now)
showNotification(R.drawable.pause_notification)
}
}
}
I have tried to do it from the documentation but didn't get it.
Thanks for the Help.

Related

Android Homescreen Widget

I am experiencing some issues with recording audio. I have created a widget button that is supposed to initiate audio recording when clicked, and stop the recording after a few seconds. However, the button doesn't seem to be working as intended. Can you please provide me with some assistance in resolving this issue?
class RecordService() : Service() {
companion object {
const val START_RECORDING_ACTION = "START_RECORDING"
}
private var recorder: MediaRecorder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
START_RECORDING_ACTION -> startRecording()
}
return super.onStartCommand(intent, flags, startId)
}
private fun startRecording() {
// Check if another recording is in progress
if (recorder != null) {
return
}
Log.d("RECORD","STARTED")
// Create a new MediaRecorder and start recording
recorder = MediaRecorder()
recorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
recorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
recorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
recorder?.setOutputFile(getOutputFile().absolutePath)
recorder?.prepare()
recorder?.start()
Handler().postDelayed({
recorder?.stop()
recorder?.release()
recorder = null
},5000)
Log.d("RECORD","STOPPED")
}
private fun getOutputFile(): File {
// Create a new file in the app's cache directory to store the recorded audio
val fileName = "recording_${System.currentTimeMillis()}.mp4"
return File(cacheDir, fileName)
}
override fun onDestroy() {
super.onDestroy()
// Stop and release the MediaRecorder when the service is destroyed
recorder?.stop()
recorder?.release()
recorder = null
}
override fun onBind(intent: Intent): IBinder? {
return null
}
}
class RecordWidget : AppWidgetProvider() {
#SuppressLint("RemoteViewLayout")
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
appWidgetIds.forEach { appWidgetId ->
// Get the layout for the App Widget and attach an OnClickListener to the button
val views = RemoteViews(context.packageName, R.layout.widget_layout)
views.setOnClickPendingIntent(
R.id.record_button,
getRecordPendingIntent(context)
)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
private fun getRecordPendingIntent(context: Context): PendingIntent {
// Create an Intent to start a service for recording audio
val intent = Intent(context, RecordService::class.java)
intent.action = RecordService.START_RECORDING_ACTION
// Create a PendingIntent to start the service when the button is clicked
return PendingIntent.getService(
context,
0,
intent,
PendingIntent.FLAG_IMMUTABLE
)
}
}
I have tried it in this way also. It is working fine but the audio is not present in the output file.
class RecordWidget : AppWidgetProvider() {
val executorService = Executors.newSingleThreadExecutor()
var mediaRecorder: MediaRecorder? = null
#SuppressLint("RemoteViewLayout")
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (widgetIDs in appWidgetIds) {
updateAppWidget(context, appWidgetManager, widgetIDs)
}
}
private fun pendingIntent(
context: Context?,
action: String
): PendingIntent? {
val intent = Intent(context, javaClass)
intent.action = action
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)
}
private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val views = RemoteViews(context.packageName, R.layout.widget_layout)
views.setOnClickPendingIntent(R.id.record_button, pendingIntent(context, "TOAST"))
views.setOnClickPendingIntent(R.id.stopBtn, pendingIntent(context, "STOP"))
appWidgetManager.updateAppWidget(appWidgetId, views)
}
private fun updateWidgets(context: Context) {
val manager = AppWidgetManager.getInstance(context)
val ids = manager.getAppWidgetIds(ComponentName(context, javaClass))
ids.forEach { id ->
updateAppWidget(context, manager, id)
}
}
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
val action = intent?.action ?: ""
if (action == "TOAST") {
executorService.execute(object : Runnable {
override fun run() {
mediaRecorder = MediaRecorder()
mediaRecorder?.reset()
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
val contextWrapper = ContextWrapper(context?.applicationContext)
val musicDirectory =
contextWrapper.getExternalFilesDir(Environment.DIRECTORY_MUSIC)
val file = File(musicDirectory, "recording10" + ".mp3").path
mediaRecorder?.setOutputFile(file)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
try {
mediaRecorder?.prepare()
} catch (e: Exception) {
e.printStackTrace()
}
mediaRecorder?.start()
}
})
Toast.makeText(context, "Recording Started", Toast.LENGTH_SHORT).show()
} else if (action == "STOP") {
executorService.execute(object : Runnable {
override fun run() {
mediaRecorder?.stop()
mediaRecorder?.release()
mediaRecorder = null
}
})
Toast.makeText(context, "Recording Stopped", Toast.LENGTH_SHORT).show()
try {
// val mediaPlayer= MediaPlayer()
// val contextWrapper = ContextWrapper(context?.applicationContext)
// val musicDirectory = contextWrapper.getExternalFilesDir(Environment.DIRECTORY_MUSIC)
// val file = File(musicDirectory, "recording8" + ".mp3").path
// Toast.makeText(context, file.toString(), Toast.LENGTH_SHORT).show()
// mediaPlayer.setDataSource(file)
// mediaPlayer.prepare()
// mediaPlayer.start()
// Toast.makeText(context, "Playing", Toast.LENGTH_SHORT).show()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}

Fatal Exception: java.lang.SecurityException Need android.permission.BLUETOOTH_CONNECT permission for android 12

fun connect(address: String?): Boolean {
if (mBluetoothAdapter == null || address == null) {
return false
}
try {
if(BluetoothAdapter.checkBluetoothAddress(address)) {
device = mBluetoothAdapter?.getRemoteDevice(address)
} else {
Toast.makeText(this, "Invalid MAC: Address", Toast.LENGTH_LONG).show()
}
} catch (e: IllegalArgumentException) {
e.printStackTrace()
} catch (e: IllegalStateException) {
e.printStackTrace()
}
if (device == null) {
return false
}
mBluetoothGatt = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
device?.connectGatt(
this, false, mGattCallback,
BluetoothDevice.TRANSPORT_LE
)
} else {
device?.connectGatt(this, false, mGattCallback)
}
Log.d(TAG, "Trying to create a new connection.")
mBluetoothDeviceAddress = address
mConnectionState = STATE_CONNECTING
return true
}
So if you already requested the Bluetooth permission in the manifest next thing to do is to ask the user to provide it to the app. An example how to do this is written in Kotlin:
fun getBluetoothPermission() {
// Check if SDK is 31+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
requestPermission.launch(Manifest.permission.BLUETOOTH_CONNECT)
} else {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
requestBluetooth.launch(enableBtIntent)
}
}
private var requestBluetooth = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
//granted
} else {
//deny
}
}
private val requestPermission =
registerForActivityResult(ActivityResultContracts.RequestPermissions()) { permission -> Log.d(permission) }
N.B. - not tested but should work.
EDIT:
You can also do for multiple permissions:
fun getBluetoothPermission() {
// Check if SDK is 31+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
requestMultiplePermissions.launch(arrayOf(
Manifest.permission.BLUETOOTH_LE,
Manifest.permission.BLUETOOTH_CONNECT))
} else {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
requestBluetooth.launch(enableBtIntent)
}
}
private val requestMultiplePermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
permissions.entries.forEach {
Log.d("Permission: ", "${it.key} = ${it.value}")
}
}

java.lang.StackOverflowError: stack size 8192KB bluetooth manager [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Bluetooth Class for views
class BluetoothClass : AppCompatActivity() {
var mBluetoothAdapter: BluetoothAdapter? = null
lateinit var m_pairedDevices: Set<BluetoothDevice>
var discover_btn: Button? = null
var deviceHardwareAddress :String?=null
val REQUEST_ENABLE_BLUETOOTH = 1
val deviceList: ArrayList<String> = ArrayList(
val TAG = "BluetoothManager2"
val bmanager:BluetoothManagerClass=BluetoothManagerClass()
var btnEnableDisable_Discoverable: Button? = null
var btnONOFF: Button? = null
var mBTDevices = java.util.ArrayList<BluetoothDevice>()
var mDeviceListAdapter: BluetoothListAdapter? = null
var listview_discover: ListView? = null
var deviceName = String()
companion object {
val EXTRA_ADDRESS: String = "Device_address"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.bluetooth_access)
listview_discover = findViewById<View>(R.id.discover_bluetoot_list) as ListView
discover_btn = findViewById<View>(R.id.discover_button) as Button
btnONOFF = findViewById(R.id.onoffdiscover_button)
btnEnableDisable_Discoverable =
findViewById(R.id.enablediscover_button)
bmanager.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
mBTDevices = java.util.ArrayList()
select_device_refresh.setOnClickListener { pairedDeviceList()
}
btnONOFF!!.setOnClickListener {
bmanager.enableDisableBT()
Log.d(this.TAG, "onClick: enabling/disabling bluetooth.")
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
if (resultCode == Activity.RESULT_OK) {
if (bmanager.mBluetoothAdapter!!.isEnabled) {
Toast.makeText(this, "Bluetooth has been enabled", Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(this, "Bluetooth has been disabled", Toast.LENGTH_SHORT)
.show();
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "Bluetooth enabling has been canceled", Toast.LENGTH_SHORT)
.show();
}
}
}
fun btnEnableDisable_Discoverable(view: View?) {
Log.d(
this.TAG,
"btnEnableDisable_Discoverable: Making device discoverable for 300 seconds."
)
bmanager.enalbedisablediscovery()
}
#RequiresApi(Build.VERSION_CODES.M)
fun checkBTPermissions() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
var permissionCheck =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION")
} else {
TODO("VERSION.SDK_INT < M")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
permissionCheck += checkSelfPermission("Manifest.permission.ACCESS_COARSE_LOCATION")
} else {
TODO("VERSION.SDK_INT < M")
}
if (permissionCheck != 0) {
requestPermissions(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
), 1001
) //Any number
}
} else {
Log.d(
this.TAG,
"checkBTPermissions: No need to check permissions. SDK version < LOLLIPOP."
)
}
}
#RequiresApi(Build.VERSION_CODES.M)
fun btnDiscover(view: View?) {
Log.d(this.TAG, "btnDiscover: Looking for unpaired devices.")
bmanager.discovering()
bmanager.startdiscovering()
}
fun pairedDeviceList() {
m_pairedDevices = bmanager.mBluetoothAdapter!!.bondedDevices
val list: ArrayList<BluetoothDevice> = ArrayList()
if (!m_pairedDevices.isEmpty()) {
for (device: BluetoothDevice in m_pairedDevices) {
list.add(device)
Log.i("device", "" + device)
}
} else {
Toast.makeText(this, "no paired bluetooth devices found", Toast.LENGTH_SHORT)
.show();
}
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, list)
select_device_list.adapter = adapter
select_device_list.onItemClickListener =
AdapterView.OnItemClickListener { _, _, position, _ ->
val device: BluetoothDevice = list[position]
val address: String = device.name.toString()
val intent = Intent(this, BluetoothControl::class.java)
intent.putExtra(BluetoothClass.EXTRA_ADDRESS, address)
startActivity(intent)
}
}
}
Bluetooth manager class for receivers
class BluetoothManagerClass {
val device=String
var mBluetoothAdapter: BluetoothAdapter? = null``
lateinit var m_pairedDevices: Set
var discover_btn: Button? = null
var deviceHardwareAddress :String?=null
val REQUEST_ENABLE_BLUETOOTH = 1
//val deviceList: ArrayList = ArrayList()
val TAG = "BluetoothManager"
var btnEnableDisable_Discoverable: Button? = null
var btnONOFF: Button? = null
var mDeviceListAdapter: BluetoothListAdapter? = null
var listview_discover: ListView? = null
private var myApiClass: BluetoothClass =
BluetoothClass()
var deviceName = String()
companion object {
val EXTRA_ADDRESS: String = "Device_address"
}
#RequiresApi(Build.VERSION_CODES.M)
fun discovering() {
if (this.mBluetoothAdapter!!.isDiscovering) {
this.mBluetoothAdapter!!.cancelDiscovery()
Log.d(this.TAG, "btnDiscover: Canceling discovery.")
//check BT permissions in manifest
myApiClass.checkBTPermissions()
this.mBluetoothAdapter!!.startDiscovery()
val discoverDevicesIntent = IntentFilter(BluetoothDevice.ACTION_FOUND)
myApiClass.registerReceiver(mBroadcastDiscovernewDevice, discoverDevicesIntent)
}
}
#RequiresApi(Build.VERSION_CODES.M)
fun startdiscovering(){
if (!this.mBluetoothAdapter!!.isDiscovering) { //check BT permissions in manifest
myApiClass.checkBTPermissions()
this.mBluetoothAdapter!!.startDiscovery()
val discoverDevicesIntent = IntentFilter(BluetoothDevice.ACTION_FOUND)
myApiClass.registerReceiver(mBroadcastDiscovernewDevice, discoverDevicesIntent)
}
}
fun enalbedisablediscovery(){
val discoverableIntent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
myApiClass. startActivity(discoverableIntent)
val intentFilter = IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)
myApiClass.registerReceiver(mBroadcastDiscoverable, intentFilter)
}
fun enableDisableBT() {
if (this.mBluetoothAdapter == null) {
Log.d(this.TAG, "enableDisableBT: Does not have BT capabilities.")
}
if (!this.mBluetoothAdapter!!.isEnabled) {
Log.d(this.TAG, "enableDisableBT: enabling BT.")
val enableBTIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
myApiClass.startActivity(enableBTIntent)
val BTIntent = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
myApiClass.registerReceiver(mBroadcastBluetoothOnOff, BTIntent)
}
if (this.mBluetoothAdapter!!.isEnabled) {
Log.d(this.TAG, "enableDisableBT: disabling BT.")
this.mBluetoothAdapter!!.disable()
val BTIntent = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
myApiClass.registerReceiver(mBroadcastBluetoothOnOff, BTIntent)
}
}
private val mBroadcastBluetoothOnOff: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
// When discovery finds a device
if (action == BluetoothAdapter.ACTION_STATE_CHANGED) {
val state =
intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
when (state) {
BluetoothAdapter.STATE_OFF ->
Log.d(ContentValues.TAG, "onReceive: STATE OFF")
BluetoothAdapter.STATE_TURNING_OFF -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver1: STATE TURNING OFF"
)
BluetoothAdapter.STATE_ON -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver1: STATE ON"
)
BluetoothAdapter.STATE_TURNING_ON -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver1: STATE TURNING ON"
)
}
}
}
}
val mBroadcastDiscovernewDevice: BroadcastReceiver = object : BroadcastReceiver() {
val arrayList = ArrayList<String>()
var deviceName = String()
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
Log.d(ContentValues.TAG, "onReceive: ACTION FOUND.")
if (action == BluetoothDevice.ACTION_FOUND) {
val device =
intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
Log.d(
ContentValues.TAG,
"onReceive: " + device.name + ": " + device.address
)
deviceName = device.name
val deviceHardwareAddress = device.address
arrayList.add(deviceName)
var mBTDevices = java.util.ArrayList<BluetoothDevice>()
mBTDevices = java.util.ArrayList()
var mDeviceListAdapter: BluetoothListAdapter? = null
var listview_discover: ListView? = null
mDeviceListAdapter =
BluetoothListAdapter(context, R.layout.device_adapter_view, mBTDevices)
listview_discover!!.setAdapter(mDeviceListAdapter)
mBTDevices.add(device)
}
}
}
val mBroadcastDiscoverable: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (action == BluetoothAdapter.ACTION_SCAN_MODE_CHANGED) {
val mode =
intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.ERROR)
when (mode) {
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver2: Discoverability Enabled."
)
BluetoothAdapter.SCAN_MODE_CONNECTABLE -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver2: Discoverability Disabled. Able to receive connections."
)
BluetoothAdapter.SCAN_MODE_NONE -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver2: Discoverability Disabled. Not able to receive connections."
)
BluetoothAdapter.STATE_CONNECTING -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver2: Connecting...."
)
BluetoothAdapter.STATE_CONNECTED -> Log.d(
ContentValues.TAG,
"mBroadcastReceiver2: Connected."
)
}
}
}
}
Your BluetoothClass instantiates a BluetoothManagerClass instance in its init. Your BluetoothManagerClass instantiates a BluetoothClass in its init. That causes an infinite loop until stack space runs out.
BluetoothClass is-a Activity and you should not be instantiating activities yourself anyway. Consider e.g. passing your BluetoothClass instance reference as a parameter to BluetoothManagerClass.

Disable GPS without redirect to device Setting Screen

I want to implement functionality when an app goes in the background the GPS should automatically Off and when an app in the foreground the GPS should automatically On. I've referred https://stackoverflow.com/a/44668999/9635628 for Enable GPS It's working fine but how can I disable when an app goes in the background?
Please, help me to solve it!
I've tried below code
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.d("App", "App in background")
offGPS()
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d("App", "App in foreground")
enableLoc()
}
}
private fun enableLoc() {
if (googleApiClient == null) {
googleApiClient = GoogleApiClient.Builder(this#MainActivity)
.addApi(LocationServices.API)
.addConnectionCallbacks(object : GoogleApiClient.ConnectionCallbacks {
override fun onConnected(bundle: Bundle?) {
}
override fun onConnectionSuspended(i: Int) {
googleApiClient!!.connect()
}
})
.addOnConnectionFailedListener { connectionResult -> Log.d("Location error", "Location error " + connectionResult.errorCode) }.build()
googleApiClient!!.connect()
val locationRequest = LocationRequest.create()
locationRequest.priority = LocationRequest.PRIORITY_NO_POWER
locationRequest.interval = (30 * 1000).toLong()
locationRequest.fastestInterval = (5 * 1000).toLong()
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
builder.setAlwaysShow(true)
val result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build())
result.setResultCallback(object : ResultCallback<LocationSettingsResult> {
override fun onResult(result: LocationSettingsResult) {
val status = result.status
when (status.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(this#MainActivity, REQUEST_LOCATION)
// finish()
} catch (e: IntentSender.SendIntentException) {
// Ignore the error.
}
}
}
})
}
}
fun offGPS() {
var provider = Settings.Secure.getString(contentResolver, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
if (provider.contains("gps")) { //if gps is enabled
var poke: Intent = Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
Second solution is
/**
* Method checks if the app is in background or not
*/
fun isAppIsInBackground(context : Context) : Boolean{
var isInBackground = true
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
val runningProcesses = am.runningAppProcesses
for (processInfo in runningProcesses) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
for (activeProcess in processInfo.pkgList) {
if (activeProcess.equals(context.packageName)) {
isInBackground = false
}
}
}
}
} else {
val taskInfo = am.getRunningTasks(1)
val componentInfo = taskInfo.get(0).topActivity
if (componentInfo.packageName.equals(context.packageName)) {
isInBackground = false
}
}
return isInBackground
}
Try this solution
private void turnGPSOff() {
String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if(provider.contains("gps")){ //if gps is enabled
final Intent poke = new Intent();
poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
sendBroadcast(poke);
}
}
Hope this will work for you.
First, in your Application class you should register a detector like this:
registerActivityLifecycleCallbacks(new Detector());
In the detector, which is an instance of Application.ActivityLifecycleCallbacks you should keep a count of activities resumed and paused like this:
/**Detector class**/
#Override
public void onActivityResumed(Activity activity) {
mActivitiesResumed++;
if (mInBackground) {
mInBackground = false;
// App is in background
}
}
#Override
public void onActivityPaused(Activity activity) {
mActivitiesResumed--;
}
#Override
public void onActivityStopped(Activity activity) {
if (mActivitiesResumed == 0) {
mInBackground = true;
// App is in foreground
}
}
And that should be it. I've this class working in production flawlessly.

Is there a way to distinguish between source of voice in a telephonic call

I've a telephonic calls recorder app that work with the below code:
var IS_SERVICE_RUNNING = false
class AudioService : Service(), MediaRecorder.OnInfoListener {
lateinit var context: Context
private var mRecorder: MediaRecorder? = null
//setting maximum file size to be recorded
private val Audio_MAX_FILE_SIZE: Long = 1000000//1Mb
private var mOutputFile: File? = null
private var mStartTime: Long = 0
private val outputFile: File
get() {
val dateFormat = SimpleDateFormat("MMdd_HHmm", Locale.US)
return File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), // Environment.DIRECTORY_DOCUMENTS, // context.filesDir, //
// .absolutePath.toString()
"call_" // "/Voice Recorder/RECORDING_"
+ dateFormat.format(Date())
+ ".m4a")
}
override fun onInfo(mr: MediaRecorder?, what: Int, extra: Int) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
stopRecording(true)
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
context = this
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
Toast.makeText(context,"started recording", Toast.LENGTH_LONG).show()
val downloadIntent = Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
val pendingIntent = PendingIntent.getActivity(context, 0, downloadIntent, 0)
val notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder(context, NotificationService.CHANNEL_ID)
} else {
Notification.Builder(context)
}.apply {
setContentIntent(pendingIntent)
setSmallIcon(R.drawable.ic_error_black_24dp)
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
setAutoCancel(true)
setContentTitle(resources.getString(R.string.recording_title))
setStyle(Notification.BigTextStyle()
.bigText(resources.getString(R.string.recording_body)))
setContentText(resources.getString(R.string.recording_body))
}.build()
val nManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// Start foreground service.
startForeground(1, notification);
} else {
nManager.notify(1, notification)
}
mRecorder = MediaRecorder().apply {
// reset()
}
mRecorder!!.setOnInfoListener(this)
mOutputFile = outputFile
mOutputFile!!.parentFile.mkdirs()
mRecorder = MediaRecorder()
mRecorder!!.apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
// setMaxFileSize(Audio_MAX_FILE_SIZE)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
// setOutputFile(mFileName)
setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC)
setAudioEncodingBitRate(48000)
setAudioSamplingRate(16000)
setOutputFile(mOutputFile!!.absolutePath)
}
try {
mRecorder!!.prepare()
mRecorder!!.start()
} catch (ise: IllegalStateException) {
Toast.makeText(context,"Error 1 $ise ", Toast.LENGTH_LONG).show()
} catch (ioe: IOException) {
Toast.makeText(context,"Error 2 $ioe ", Toast.LENGTH_LONG).show()
}
return Service.START_STICKY
}
private fun stopRecording(saveFile: Boolean) {
Toast.makeText(context,"stopped recording ", Toast.LENGTH_LONG).show()
mRecorder!!.apply {
stop()
reset()
release()
}
mRecorder = null
mStartTime = 0
if (!saveFile && mOutputFile != null) {
mOutputFile!!.delete()
}
// Stop foreground service and remove the notification.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(false)
} else stopSelf()
}
override fun onDestroy() {
super.onDestroy()
// Toast.makeText(context,"service destroyed ", Toast.LENGTH_LONG).show()
stopRecording(true)
}
}
That is started from the below code:
class PhoneStateReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
prefs = context.getSharedPreferences(PREFS_FILENAME, 0)
val record_calls = prefs!!.getBoolean("recordCalls", false)
val service = Intent(context, AudioService::class.java)
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
when(state){
TelephonyManager.EXTRA_STATE_RINGING -> {
}
TelephonyManager.EXTRA_STATE_OFFHOOK -> {
if (record_calls) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(service)
} else context.startService(service)
}
}
TelephonyManager.EXTRA_STATE_IDLE -> {
if (IS_SERVICE_RUNNING) context.stopService(service)
}
else -> Toast.makeText(context, "ERROR", Toast.LENGTH_LONG).show()
}
}
}
Is there a way to recognize if the voice heard is from my device or from the other person person on the line, so I can decide if I need to filter both sides talks or one side call only (the other one talks)!

Categories

Resources