universal7885: fm-app: Refactor

This commit is contained in:
roynatech2544 2022-10-21 22:53:17 +09:00
commit 1fd4442a64
12 changed files with 197 additions and 433 deletions

View file

@ -8,12 +8,11 @@ android_app {
static_libs: [
"androidx.core_core",
"androidx.appcompat_appcompat",
"androidx.preference_preference",
"com.google.android.material_stable",
"kotlinx_coroutines",
"androidx.transition_transition",
"kotlinx_coroutines_android",
"androidx.coordinatorlayout_coordinatorlayout",
"vendor.eureka.hardware.fmradio-V1-java",
"vendor.eureka.hardware.fmradio-V2-java",
],
required: [
"vendor.eureka.hardware.fmradio-service",

View file

@ -10,29 +10,23 @@ import android.media.MediaMetadata
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.os.IBinder
import com.eurekateam.fmradio.enums.OutputState
import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.enums.PlayState
import com.eurekateam.fmradio.enums.PowerState
import com.eurekateam.fmradio.fragments.MainFragment
import com.eurekateam.fmradio.utils.Log
import vendor.eureka.hardware.fmradio.SetType
import vendor.eureka.hardware.fmradio.GetType
class FMRadioService : Service() {
private lateinit var mContext: Context
private lateinit var mAudioManager: AudioManager
private lateinit var mTracks: IntArray
private lateinit var mNativeFMInterface: NativeFMInterface
private val mNativeFMInterface = NativeFMInterface()
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i("--- FMRadio Background (IN) ---")
fd = MainFragment.fd
mAudioManager = getSystemService(AUDIO_SERVICE) as AudioManager
mTracks = MainFragment.mTracks
mIndex = MainFragment.getIndex()
if (mTracks.isEmpty() || mIndex == -1) {
return super.onStartCommand(intent, flags, startId)
}
if (intent != null) {
intent.action?.let { Log.i(it) }
when (intent.action) {
@ -47,51 +41,37 @@ class FMRadioService : Service() {
}
ACTION_BEFORE -> {
mPlayState = PlayState.STATE_PLAYING
Log.i("mCurrentIndex $mIndex")
if (mIndex > 0) {
mIndex -= 1
}
mNativeFMInterface.setFMFreq(fd, mTracks[mIndex].toInt())
MainFragment.mFreqCurrent = mTracks[mIndex].toInt()
mNativeFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_BEFORE_CHANNEL)
}
ACTION_NEXT -> {
mPlayState = PlayState.STATE_PLAYING
Log.i("mCurrentIndex $mIndex")
if (mIndex < mTracks.size - 1) {
mIndex += 1
}
mNativeFMInterface.setFMFreq(fd, mTracks[mIndex].toInt())
MainFragment.mFreqCurrent = mTracks[mIndex].toInt()
mNativeFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_NEXT_CHANNEL)
}
ACTION_QUIT -> {
mAudioManager = getSystemService(AUDIO_SERVICE) as AudioManager
Log.i("--- FMRadio Background (OUT) ---")
mNativeFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_THREAD, 0)
mNativeFMInterface.mDevCtl.close()
mAudioManager.setParameters(PowerState.FM_POWER_OFF.mAudioParam)
mMediaSession.release()
stopSelf()
}
ACTION_OUTPUT -> {
changeOutputDevice(mOutput)
if (mOutput == OutputState.OUTPUT_HEADSET) {
mOutput = OutputState.OUTPUT_SPEAKER
} else if (mOutput == OutputState.OUTPUT_SPEAKER) {
mOutput = OutputState.OUTPUT_HEADSET
}
var mSpeaker = PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("speaker", false)
mSpeaker = !mSpeaker
changeOutputDevice(mSpeaker)
PreferenceManager.getDefaultSharedPreferences(mContext).edit().putBoolean("speaker", mSpeaker).apply()
}
ACTION_START -> {
mMediaSession = MediaSession(this, "FMRadio")
mNativeFMInterface = NativeFMInterface()
mContext = this
setPlaybackState()
mMediaSession.isActive = true
}
}
}
sendMetaData("FM ${mTracks[mIndex].toFloat() / 1000} Mhz")
sendMetaData("FM ${mNativeFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_FREQ).toFloat() / 1000} Mhz")
startForeground(51, pushNotification())
if (mOutput == OutputState.OUTPUT_SPEAKER) {
changeOutputDevice(OutputState.OUTPUT_HEADSET)
}
Log.i("--- FMRadio Background (OUT) ---")
return START_STICKY
}
@ -141,13 +121,10 @@ class FMRadioService : Service() {
val close = PendingIntent.getService(mContext, 0, Intent(ACTION_QUIT), PendingIntent.FLAG_IMMUTABLE)
val output = PendingIntent.getService(mContext, 0, Intent(ACTION_OUTPUT), PendingIntent.FLAG_IMMUTABLE)
val mOutputAction: Notification.Action = Notification.Action.Builder(
when (mOutput) {
OutputState.OUTPUT_HEADSET -> {
if (PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("speaker", false)) {
Icon.createWithResource(this, R.drawable.ic_volume_up)
}
OutputState.OUTPUT_SPEAKER -> {
} else {
Icon.createWithResource(this, R.drawable.ic_headphones)
}
},
"Output Configuration",
output
@ -196,16 +173,9 @@ class FMRadioService : Service() {
private const val ACTION_QUIT = "$PACKAGENAME.QUIT"
private const val ACTION_OUTPUT = "$PACKAGENAME.OUTPUT"
private var mPlayState: PlayState = PlayState.STATE_PLAYING
private var mOutput: OutputState = MainFragment.mHeadset
private var fd: Int = -1
private var mIndex = -1
lateinit var mMediaSession: MediaSession
}
private fun changeOutputDevice(output: OutputState) {
if (output == OutputState.OUTPUT_SPEAKER) {
mNativeFMInterface.setAudioRoute(false)
} else if (output == OutputState.OUTPUT_HEADSET) {
mNativeFMInterface.setAudioRoute(true)
}
private fun changeOutputDevice(speaker: Boolean) {
mNativeFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_SPEAKER_ROUTE, if (speaker) 1 else 0)
}
}

View file

@ -47,7 +47,6 @@ class MainActivity : AppCompatActivity() {
private lateinit var mAlertImage: AppCompatImageView
private lateinit var mAudioManager: AudioManager
override fun onCreate(savedInstanceState: Bundle?) {
MainFragment.fd = mFMInterface.openFMDevice()
mAlertView = (getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater)
.inflate(R.layout.alertdialog, null)
mAlertTitle = mAlertView.findViewById(R.id.alert_title)
@ -55,27 +54,16 @@ class MainActivity : AppCompatActivity() {
mAlertDesc = mAlertView.findViewById(R.id.alert_desc)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
if (MainFragment.fd == -1) {
Log.e("CANNOT OPEN /dev/radio0!!!")
mAlertTitle.text = getString(R.string.radio_io_error)
mAlertDesc.text = getString(R.string.radio_io_error_desc)
mAlertImage.setImageIcon(Icon.createWithResource(this, R.drawable.ic_error))
val mAlertDialog = AlertDialog.Builder(this)
mAlertDialog
.setCancelable(false)
.setView(mAlertView)
.setNegativeButton(R.string.ok) { _: DialogInterface, _: Int ->
finish()
}
.show()
}
DynamicColors.applyToActivitiesIfAvailable(application)
mFMInterface.mDevCtl.open()
mAudioManager = getSystemService(AUDIO_SERVICE) as AudioManager
/**
* Detects whether wired headphones is connected to this device or no
* @see AudioManager.getDevices
*/
val mAudioDeviceInfo = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
for (i in mAudioDeviceInfo.indices) {
if (mAudioDeviceInfo[i].type == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
mAudioDeviceInfo[i].type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
@ -84,6 +72,7 @@ class MainActivity : AppCompatActivity() {
Log.i("Wired Headphones detected")
}
}
if (MainFragment.mHeadSetPlugged != HeadsetState.HEADSET_STATE_CONNECTED) {
mAlertTitle.text = getString(R.string.no_headphones_error)
mAlertDesc.text = getString(R.string.no_headphones_error_desc)
@ -183,6 +172,7 @@ class MainActivity : AppCompatActivity() {
super.onRestart()
stopService(mIntent)
}
companion object {
private const val ACTION_START = "com.eurekateam.fmradio.START"
}

View file

@ -3,38 +3,15 @@ package com.eurekateam.fmradio
import android.os.ServiceManager
import vendor.eureka.hardware.fmradio.GetType
import vendor.eureka.hardware.fmradio.IFMDevControl
import vendor.eureka.hardware.fmradio.SetType
class NativeFMInterface {
private val mDevCtl: IFMDevControl
private val mSysfsCtl: IFMDevControl
private val mDefaultCtl: IFMDevControl
val mDevCtl: IFMDevControl
val mSysfsCtl: IFMDevControl
val mDefaultCtl: IFMDevControl
init {
mDevCtl = IFMDevControl.Stub.asInterface(ServiceManager.waitForDeclaredService("vendor.eureka.hardware.fmradio.IFMDevControl/default"))
mSysfsCtl = IFMDevControl.Stub.asInterface(ServiceManager.waitForDeclaredService("vendor.eureka.hardware.fmradio.IFMDevControl/support"))
mDefaultCtl = if (mSysfsCtl.getValue(GetType.GET_TYPE_FM_SYSFS_IF) == 0) mSysfsCtl else mDevCtl
}
fun openFMDevice(): Int {
mDevCtl.open()
return 1
}
fun getFMFreq(a: Int): Long = mDevCtl.getValue(GetType.GET_TYPE_FM_FREQ).toLong()
fun setFMFreq(a: Int, freq: Int) = mDevCtl.setValue(SetType.SET_TYPE_FM_FREQ, freq)
fun setFMVolume(a: Int, volume: Int) = mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, volume)
fun setFMMute(a: Int, mute: Boolean) = mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, if (mute) 1 else 0)
fun getFmUpper(a: Int): Int = mDevCtl.getValue(GetType.GET_TYPE_FM_UPPER_LIMIT)
fun getFMLower(a: Int): Int = mDevCtl.getValue(GetType.GET_TYPE_FM_LOWER_LIMIT)
fun getRMSSI(a: Int): Int = mDevCtl.getValue(GetType.GET_TYPE_FM_RMSSI)
fun getFMTracks(fd: Int): IntArray = mDefaultCtl.getFreqsList()
fun setFMThread(a: Int, run: Boolean) = mDevCtl.setValue(SetType.SET_TYPE_FM_THREAD, if (run) 1 else 0)
fun getNextChannel(a: Int): Int = mDefaultCtl.getValue(GetType.GET_TYPE_FM_NEXT_CHANNEL)
fun getBeforeChannel(a: Int): Int = mDefaultCtl.getValue(GetType.GET_TYPE_FM_BEFORE_CHANNEL)
fun stopSearching(a: Int) = mDevCtl.setValue(SetType.SET_TYPE_FM_SEARCH_CANCEL, 0)
fun setFMRSSI(a: Int, rssi: Long) = mDevCtl.setValue(SetType.SET_TYPE_FM_RMSSI, rssi.toInt())
fun closeFMDevice(fd: Int) = mDevCtl.close()
fun getSysfsSupport(): Boolean = mSysfsCtl.getValue(GetType.GET_TYPE_FM_SYSFS_IF) == 0
fun setAudioRoute(speaker: Boolean) = mDevCtl.setValue(SetType.SET_TYPE_FM_SPEAKER_ROUTE, if (speaker) 1 else 0)
}

View file

@ -7,26 +7,28 @@ import android.view.ViewGroup
import android.widget.BaseAdapter
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.res.ResourcesCompat
import com.eurekateam.fmradio.*
import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.fragments.MainFragment
import com.eurekateam.fmradio.utils.FileUtilities
import com.eurekateam.fmradio.utils.Log
import com.eurekateam.fmradio.R
import com.google.android.material.textview.MaterialTextView
import vendor.eureka.hardware.fmradio.GetType
import vendor.eureka.hardware.fmradio.SetType
class ListViewAdapter(private val mContext: Context) : BaseAdapter() {
private val mFMInterface = NativeFMInterface()
private val mListChannel = mFMInterface.mDefaultCtl.getFreqsList()
private var mListofViews = HashMap<Int, View>(30)
override fun getCount(): Int {
return MainFragment.mTracks.size
return 30
}
override fun getItem(p0: Int): Any {
return MainFragment.mTracks[p0]
override fun getItem(p: Int): Any {
return mListChannel[p]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
override fun getItemId(p: Int): Long {
return p.toLong()
}
override fun getView(id: Int, mConvertView: View?, parent: ViewGroup?): View {
@ -39,16 +41,10 @@ class ListViewAdapter(private val mContext: Context) : BaseAdapter() {
mAnotherConvertView.findViewById<MaterialTextView>(R.id.channel_list_title).text =
String.format(
mContext.getString(R.string.fm_radio_freq),
MainFragment.mTracks[id].toFloat() / 1000
mListChannel[id].toFloat() / 1000
)
mAnotherConvertView.findViewById<MaterialTextView>(R.id.channel_list_title).setOnClickListener {
mFMInterface.setFMFreq(MainFragment.fd, MainFragment.mTracks[id].toInt())
MainFragment.mFreqCurrent = MainFragment.mTracks[id].toInt()
FileUtilities.writeToFile(
FileUtilities.mFMFreqFileName,
MainFragment.mFreqCurrent.toString(),
mContext
)
mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_FREQ, mListChannel[id])
setCurrentFMChannel(id)
}
mAnotherConvertView.findViewById<AppCompatImageView>(R.id.star_button_list).let {
@ -58,17 +54,17 @@ class ListViewAdapter(private val mContext: Context) : BaseAdapter() {
R.drawable.ic_star_filled,
mContext.theme
)
val mIndex = MainFragment.mTracks[id].toInt()
if (MainFragment.mFavStats[mIndex] == null) {
MainFragment.mFavStats.putIfAbsent(mIndex, false)
}
if (MainFragment.mFavStats[mIndex]!!) {
it.setImageDrawable(mStarFilled)
} else {
val mIndex = mListChannel[id]
val mSharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
val mBefore = mSharedPref.getBoolean("fav_$mIndex", false)
if (mBefore) {
it.setImageDrawable(mStar)
} else {
it.setImageDrawable(mStarFilled)
}
mSharedPref.edit().putBoolean("fav_$mIndex", !mBefore).apply()
}
if (MainFragment.mFreqCurrent == MainFragment.mTracks[id].toInt()) {
if (mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_FREQ) == mListChannel[id]) {
setCurrentFMChannel(id)
}
mListofViews[id] = mAnotherConvertView!!
@ -89,7 +85,7 @@ class ListViewAdapter(private val mContext: Context) : BaseAdapter() {
mListofViews[mPosition]?.setBackgroundColor(
ResourcesCompat.getColor(
mContext.resources,
android.R.color.system_accent3_400,
android.R.color.system_accent2_400,
mContext.theme
)
)

View file

@ -6,38 +6,34 @@ import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import androidx.core.content.res.ResourcesCompat
import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.PebbleTextView
import com.eurekateam.fmradio.R
import com.eurekateam.fmradio.fragments.MainFragment
import com.eurekateam.fmradio.utils.FileUtilities
import vendor.eureka.hardware.fmradio.SetType
class PebbleLayoutAdapter(private val mContext: Context) : BaseAdapter() {
private val mFavoriteList: MutableList<Int> = emptyList<Int>().toMutableList()
private var mFavoriteList: List<Int> = emptyList()
private val mFMInterface = NativeFMInterface()
private val mListChannel = mFMInterface.mDefaultCtl.getFreqsList()
private val mSharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
init {
for (mItem in MainFragment.mFavStats) {
if (mItem.value) {
mFavoriteList.add(mItem.key)
for (k in mListChannel) {
if (mSharedPref.getBoolean("fav_$k", false)) mFavoriteList += k
}
}
mFavoriteList.sort()
var mData = ""
for (i in mFavoriteList) {
mData += "$i\n"
}
FileUtilities.writeToFile(FileUtilities.mFavouriteChannelFileName, mData, mContext)
}
override fun getCount(): Int {
return mFavoriteList.size
}
override fun getItem(p0: Int): Any {
return mFavoriteList[p0]
override fun getItem(p: Int): Any {
return mFavoriteList[p]
}
private val mFMInterface = NativeFMInterface()
override fun getItemId(p0: Int): Long {
return p0.toLong()
override fun getItemId(p: Int): Long {
return p.toLong()
}
override fun getView(id: Int, mConvertView: View?, parent: ViewGroup?): View {
@ -55,13 +51,7 @@ class PebbleLayoutAdapter(private val mContext: Context) : BaseAdapter() {
mContext.theme
)
setOnClickListener {
mFMInterface.setFMFreq(MainFragment.fd, mFavoriteList[id])
MainFragment.mFreqCurrent = mFavoriteList[id]
FileUtilities.writeToFile(
FileUtilities.mFMFreqFileName,
MainFragment.mFreqCurrent.toString(),
mContext
)
mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_FREQ, mFavoriteList[id])
}
}
return mAnotherConvertView

View file

@ -1,11 +0,0 @@
package com.eurekateam.fmradio.enums
/***
* [OUTPUT_SPEAKER] : Output to speaker
*
* [OUTPUT_HEADSET] : Output to headset
*/
enum class OutputState {
OUTPUT_SPEAKER,
OUTPUT_HEADSET
}

View file

@ -5,23 +5,27 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ListView
import androidx.fragment.app.Fragment
import com.eurekateam.fmradio.MainActivity
import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.R
import com.eurekateam.fmradio.MainActivity
import com.eurekateam.fmradio.adapters.ListViewAdapter
import com.eurekateam.fmradio.utils.IWaitUntil
import com.eurekateam.fmradio.utils.WaitUntil
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import vendor.eureka.hardware.fmradio.SetType
import vendor.eureka.hardware.fmradio.GetType
class ChannelListFragment :
Fragment(R.layout.activity_channel_list),
View.OnClickListener {
private lateinit var mListView: ListView
private lateinit var mFloatingActionButton: FloatingActionButton
private val mNativeIF = NativeFMInterface()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -51,17 +55,21 @@ class ChannelListFragment :
}
override fun onClick(v: View?) {
GlobalScope.launch {
withContext(Dispatchers.IO) {
MainFragment.mRefreshTracks()
}
withContext(Dispatchers.Main) {
mNativeIF.mDefaultCtl.setValue(SetType.SET_TYPE_FM_SEARCH_START, 0)
requireActivity().window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
WaitUntil.setTimer(
requireActivity(),
object : IWaitUntil {
override fun cond(): Boolean = mNativeIF.mDefaultCtl.getValue(GetType.GET_TYPE_FM_MUTEX_LOCKED) == 0
override fun todo() {
(requireActivity() as MainActivity).getMySupportFragmentManager().apply {
beginTransaction().remove(this@ChannelListFragment).commit()
executePendingTransactions()
beginTransaction().add(R.id.container_view, this@ChannelListFragment).commit()
}
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
}
)
}
}

View file

@ -1,6 +1,7 @@
package com.eurekateam.fmradio.fragments
import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
@ -9,25 +10,25 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.SeekBar
import android.widget.Toast
import androidx.appcompat.widget.AppCompatSeekBar
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.R
import com.eurekateam.fmradio.enums.HeadsetState
import com.eurekateam.fmradio.enums.OutputState
import com.eurekateam.fmradio.enums.PowerState
import com.eurekateam.fmradio.utils.FileUtilities
import com.eurekateam.fmradio.utils.IWaitUntil
import com.eurekateam.fmradio.utils.Log
import com.eurekateam.fmradio.utils.WaitUntil
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textview.MaterialTextView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import vendor.eureka.hardware.fmradio.SetType
import vendor.eureka.hardware.fmradio.GetType
import java.text.DecimalFormat
class MainFragment :
@ -48,6 +49,9 @@ class MainFragment :
private lateinit var mAudioManager: AudioManager
private lateinit var mStar: Drawable
private lateinit var mStarFilled: Drawable
private lateinit var mFavList: List<Int>
private lateinit var mSharedPref: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -83,6 +87,7 @@ class MainFragment :
mNextChannelBtn.setOnClickListener(this)
mOutputSwitch.setOnClickListener(this)
mFavButton.setOnClickListener(this)
mSharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext())
var mIsLight = true
val nightModeFlags = requireContext().resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK
@ -108,96 +113,33 @@ class MainFragment :
setBackgroundColor(resources.getColor(android.R.color.system_accent1_700, requireContext().theme))
}
}
GlobalScope.launch {
withContext(Dispatchers.IO) {
if (FileUtilities.checkIfExistFile(FileUtilities.mFavouriteChannelFileName, requireContext())) {
val mFavData = FileUtilities.readFromFile(
FileUtilities.mFavouriteChannelFileName,
requireContext()
)
for (mItem in mFavData.split("\\r?\\n".toRegex())) {
if (mItem.isNotBlank()) {
mFavStats[mItem.toInt()] = true
}
}
}
var mMute = false
if (mFreqCurrent == -1) {
mAudioManager.setParameters(PowerState.FM_POWER_OFF.mAudioParam)
withContext(Dispatchers.Main) {
mUpdateEnableDisable(false, mRootView)
}
mMute = true
}
if (FileUtilities.checkIfExistFile(FileUtilities.mFMFreqFileName, requireContext())) {
mFreqCurrent = FileUtilities.readFromFile(
FileUtilities.mFMFreqFileName,
requireContext()
).toInt()
mFMInterface.setFMFreq(fd, mFreqCurrent)
withContext(Dispatchers.Main) {
mFMFreq.text = mCleanFormat.format(mFreqCurrent.toFloat() / 1000)
}
}
if (FileUtilities.checkIfExistFile(FileUtilities.mFMVolumeFileName, requireContext())) {
mVolume = FileUtilities.readFromFile(
FileUtilities.mFMVolumeFileName,
requireContext()
).toInt()
mFMInterface.setFMVolume(fd, mVolume)
withContext(Dispatchers.Main) {
mSeekBar.progress = mVolume
}
}
withContext(Dispatchers.Main) {
val mVolume = mSharedPref.getInt("volume", 8)
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, mVolume)
mSeekBar.min = 1
mSeekBar.max = 15
}
withContext(Dispatchers.IO) {
if (mVolume == -1) {
mVolume = 8
mFMInterface.setFMVolume(fd, mVolume)
withContext(Dispatchers.Main) {
mSeekBar.progress = mVolume
val mRestoreFreq = mSharedPref.getInt("freq", mFMInterface.mDevCtl.getValue(GetType.GET_TYPE_FM_LOWER_LIMIT))
mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_FREQ, mRestoreFreq)
mFMFreq.text = mCleanFormat.format(mRestoreFreq.toFloat() / 1000)
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_THREAD, 1)
Toast.makeText(requireContext(), "Updating freqs list... Please wait", Toast.LENGTH_LONG).show()
requireActivity().window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_SEARCH_START, 0)
WaitUntil.setTimer(
requireActivity(),
object : IWaitUntil {
override fun cond(): Boolean = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_MUTEX_LOCKED) == 0
override fun todo() {
val mList = mFMInterface.mDefaultCtl.getFreqsList()
for (i in mList) {
if (mSharedPref.getBoolean("fav_$i", false)) mFavList += i
}
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
Toast.makeText(requireContext(), "Done", Toast.LENGTH_SHORT).show()
}
}
}
if (!mMute) {
mFMInterface.setFMMute(fd, true)
}
mFMInterface.setFMFreq(fd, mFMInterface.getFMLower(fd))
mRefreshTracks()
if (mFreqCurrent != -1) {
mFMInterface.setFMFreq(fd, mFreqCurrent)
} else {
mFreqCurrent = mFMInterface.getFMLower(fd)
}
mFreqCurrent = mFMInterface.getFMFreq(fd).toInt()
mFMInterface.setFMFreq(fd, mFreqCurrent)
withContext(Dispatchers.Main) {
mFMFreq.text = mCleanFormat.format(mFreqCurrent.toFloat() / 1000)
}
if (!mMute) {
mFMInterface.setFMMute(fd, false)
}
if (mFreqCurrent == -1) {
mFMInterface.setFMThread(fd, true)
}
withContext(Dispatchers.Main) {
mFavButton.let {
if (mFavStats[mFreqCurrent] == null) {
mFavStats.putIfAbsent(mFreqCurrent, false)
}
if (mFavStats[mFreqCurrent]!!) {
it.setImageDrawable(mStarFilled)
} else {
it.setImageDrawable(mStar)
}
}
}
}
}
)
// Update track list and fav button
return mRootView
}
@ -257,85 +199,55 @@ class MainFragment :
override fun onClick(v: View) {
when (v.id) {
mOutputSwitch.id -> {
if (mHeadset == OutputState.OUTPUT_HEADSET) {
val mCurrent = mSharedPref.getBoolean("speaker", false)
if (!mCurrent) {
mOutputSwitch.setImageIcon(
Icon.createWithResource(
requireContext(),
R.drawable.ic_volume_up
)
)
val ret = mFMInterface.setAudioRoute(true)
Log.i("mFMInterface.setAudioRoute return $ret")
} else if (mHeadset == OutputState.OUTPUT_SPEAKER) {
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_SPEAKER_ROUTE, 1)
} else {
mOutputSwitch.setImageIcon(
Icon.createWithResource(
requireContext(),
R.drawable.ic_headphones
)
)
val ret = mFMInterface.setAudioRoute(false)
Log.i("mFMInterface.setAudioRoute return $ret")
}
if (mHeadset == OutputState.OUTPUT_HEADSET) {
mHeadset = OutputState.OUTPUT_SPEAKER
} else if (mHeadset == OutputState.OUTPUT_SPEAKER) {
mHeadset = OutputState.OUTPUT_HEADSET
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_SPEAKER_ROUTE, 0)
}
mSharedPref.edit().putBoolean("speaker", !mCurrent).apply()
}
mVolumeUp.id -> {
if (mVolume < 15) {
mVolume += 1
var mCurrentVolume = mSharedPref.getInt("volume", 8)
if (mCurrentVolume < 15) {
mCurrentVolume = mCurrentVolume + 1
}
mFMInterface.setFMVolume(fd, mVolume)
mSeekBar.progress = mVolume
Toast.makeText(requireContext(), "Volume set to $mVolume", Toast.LENGTH_SHORT).show()
FileUtilities.writeToFile(
FileUtilities.mFMVolumeFileName,
mVolume.toString(),
requireContext()
)
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, mCurrentVolume)
mSeekBar.progress = mCurrentVolume
Toast.makeText(requireContext(), "Volume set to $mCurrentVolume", Toast.LENGTH_SHORT).show()
mSharedPref.edit().putInt("volume", mCurrentVolume).apply()
}
mVolumeDown.id -> {
if (mVolume > 0) {
mVolume -= 1
var mCurrentVolume = mSharedPref.getInt("volume", 8)
if (mCurrentVolume > 0) {
mCurrentVolume = mCurrentVolume - 1
}
mFMInterface.setFMVolume(fd, mVolume)
mSeekBar.progress = mVolume
Toast.makeText(requireContext(), "Volume set to $mVolume", Toast.LENGTH_SHORT).show()
FileUtilities.writeToFile(
FileUtilities.mFMVolumeFileName,
mVolume.toString(),
requireContext()
)
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, mCurrentVolume)
mSeekBar.progress = mCurrentVolume
Toast.makeText(requireContext(), "Volume set to $mCurrentVolume", Toast.LENGTH_SHORT).show()
mSharedPref.edit().putInt("volume", mCurrentVolume).apply()
}
mBeforeChannelBtn.id -> {
mFMInterface.setFMMute(fd, true)
val mTempFreq = mFMInterface.getBeforeChannel(fd)
if (mTempFreq > mFMInterface.getFMLower(fd) && mTempFreq < mFMInterface.getFmUpper(
fd
)
) {
mFreqCurrent = mTempFreq
}
if (!mFMInterface.getSysfsSupport()) {
mFMInterface.setFMFreq(fd, mFreqCurrent)
}
mFMInterface.setFMMute(fd, false)
FileUtilities.writeToFile(
FileUtilities.mFMFreqFileName,
mFreqCurrent.toString(),
requireContext()
)
mFavButton.let {
if (mFavStats[mFreqCurrent] == null) {
mFavStats.putIfAbsent(mFreqCurrent, false)
}
if (mFavStats[mFreqCurrent]!!) {
it.setImageDrawable(mStarFilled)
} else {
it.setImageDrawable(mStar)
}
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 1)
val mNewFreq = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_BEFORE_CHANNEL)
mFMFreq.text = mCleanFormat.format(mNewFreq.toFloat() / 1000)
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 0)
if (mSharedPref.getBoolean("fav_$mNewFreq", false)) {
mFavButton.setImageDrawable(mStarFilled)
}
mSharedPref.edit().putInt("freq", mNewFreq).apply()
}
mPowerBtn.id -> {
if (mFMPower) {
@ -343,89 +255,40 @@ class MainFragment :
mFMFreq.text = getText(R.string.inital_freq)
} else {
mAudioManager.setParameters(PowerState.FM_POWER_ON.mAudioParam)
mFMFreq.text = mCleanFormat.format(mFreqCurrent.toFloat() / 1000)
mFMFreq.text = mCleanFormat.format(mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_FREQ).toFloat() / 1000)
}
mUpdateEnableDisable(!mFMPower)
mFMPower = !mFMPower
}
mNextChannelBtn.id -> {
mFMInterface.setFMMute(fd, true)
val mTempFreq = mFMInterface.getNextChannel(fd)
if (mTempFreq > mFMInterface.getFMLower(fd) && mTempFreq < mFMInterface.getFmUpper(
fd
)
) {
mFreqCurrent = mTempFreq
}
if (!mFMInterface.getSysfsSupport()) {
mFMInterface.setFMFreq(fd, mFreqCurrent)
}
mFMInterface.setFMMute(fd, false)
FileUtilities.writeToFile(
FileUtilities.mFMFreqFileName,
mFreqCurrent.toString(),
requireContext()
)
mFavButton.let {
if (mFavStats[mFreqCurrent] == null) {
mFavStats.putIfAbsent(mFreqCurrent, false)
}
if (mFavStats[mFreqCurrent]!!) {
it.setImageDrawable(mStarFilled)
} else {
it.setImageDrawable(mStar)
}
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 1)
val mNewFreq = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_NEXT_CHANNEL)
mFMFreq.text = mCleanFormat.format(mNewFreq.toFloat() / 1000)
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 0)
if (mSharedPref.getBoolean("fav_$mNewFreq", false)) {
mFavButton.setImageDrawable(mStarFilled)
}
mSharedPref.edit().putInt("freq", mNewFreq).apply()
}
mFavButton.id -> {
val mIndex = mFreqCurrent
if (mFavStats[mIndex] == null) {
mFavStats.putIfAbsent(mIndex, false)
}
mFavStats[mIndex] = !mFavStats[mIndex]!!
mFavButton.let {
if (mFavStats[mIndex]!!) {
it.setImageDrawable(mStarFilled)
} else {
it.setImageDrawable(mStar)
val mCurrFreq = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_FREQ)
val mCurr = mSharedPref.getBoolean("fav_$mCurrFreq", false)
if (mCurr) { mFavButton.setImageDrawable(mStar) } else { mFavButton.setImageDrawable(mStarFilled) }
mSharedPref.edit().putBoolean("fav_$mCurrFreq", !mCurr).apply()
}
}
Log.d(
"Fav stats for $mIndex changed. " +
"Current value ${mFavStats[mIndex]}"
)
}
}
mFMFreq.text = mCleanFormat.format(mFreqCurrent.toFloat() / 1000)
}
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
mFMInterface.setFMVolume(fd, p1)
FileUtilities.writeToFile(FileUtilities.mFMVolumeFileName, p1.toString(), requireContext())
mVolume = p1
mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, p1)
mSharedPref.edit().putInt("volume", p1).apply()
}
override fun onStartTrackingTouch(p0: SeekBar?) {}
override fun onStopTrackingTouch(p0: SeekBar?) {
Toast.makeText(requireContext(), "Volume set to $mVolume", Toast.LENGTH_SHORT).show()
}
override fun onStopTrackingTouch(p0: SeekBar?) {}
companion object {
private var mVolume = -1
var fd = -1
var mHeadset = OutputState.OUTPUT_SPEAKER
var mFreqCurrent = -1
private var mFMPower = false
var mFMPower = false
var mHeadSetPlugged: HeadsetState = HeadsetState.HEADSET_STATE_DISCONNECTED
var mTracks: IntArray = emptyArray<Int>().toIntArray()
fun mRefreshTracks() {
NativeFMInterface().setFMFreq(fd, NativeFMInterface().getFMLower(fd))
mTracks = NativeFMInterface().getFMTracks(fd)
mTracks = MainFragment().removeZeros(mTracks)
(mFreqCurrent != -1).let { NativeFMInterface().setFMFreq(fd, mFreqCurrent) }
}
fun getIndex(): Int {
return mTracks.indexOf(mFreqCurrent)
}
val mFavStats = HashMap<Int, Boolean>(30)
}
/**

View file

@ -1,48 +0,0 @@
package com.eurekateam.fmradio.utils
import android.content.Context
import java.io.*
object FileUtilities {
const val mFMFreqFileName = "fm_freq_current"
const val mFMVolumeFileName = "fm_volume_current"
const val mFavouriteChannelFileName = "fm_fav_freqs"
fun writeToFile(fileName: String, data: String, mContext: Context) {
var os: OutputStream? = null
try {
os = FileOutputStream(File(mContext.filesDir.absolutePath + "/" + fileName))
os.write(data.toByteArray(), 0, data.length)
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
os?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun readFromFile(fileName: String, mContext: Context): String {
val mFile = File(mContext.filesDir.absolutePath + "/" + fileName)
var os: InputStream? = null
val mByteArray = ByteArray(mFile.length().toInt())
try {
os = FileInputStream(mFile)
os.read(mByteArray)
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
os?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return String(mByteArray)
}
fun checkIfExistFile(fileName: String, mContext: Context): Boolean {
return File(mContext.filesDir.absolutePath + "/" + fileName).exists()
}
}

View file

@ -0,0 +1,6 @@
package com.eurekateam.fmradio.utils
interface IWaitUntil {
fun cond(): Boolean
fun todo()
}

View file

@ -0,0 +1,24 @@
package com.eurekateam.fmradio.utils
import android.app.Activity
import java.util.Timer
import java.util.TimerTask
object WaitUntil {
fun setTimer(act: Activity, todo: IWaitUntil, timeout: Long = 15000) {
Timer().schedule(
object : TimerTask() {
override fun run() {
act.runOnUiThread({
if (todo.cond()) {
todo.todo()
cancel()
}
})
}
},
timeout
)
}
}