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: [ static_libs: [
"androidx.core_core", "androidx.core_core",
"androidx.appcompat_appcompat", "androidx.appcompat_appcompat",
"androidx.preference_preference",
"com.google.android.material_stable", "com.google.android.material_stable",
"kotlinx_coroutines",
"androidx.transition_transition", "androidx.transition_transition",
"kotlinx_coroutines_android",
"androidx.coordinatorlayout_coordinatorlayout", "androidx.coordinatorlayout_coordinatorlayout",
"vendor.eureka.hardware.fmradio-V1-java", "vendor.eureka.hardware.fmradio-V2-java",
], ],
required: [ required: [
"vendor.eureka.hardware.fmradio-service", "vendor.eureka.hardware.fmradio-service",

View file

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

View file

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

View file

@ -3,38 +3,15 @@ package com.eurekateam.fmradio
import android.os.ServiceManager import android.os.ServiceManager
import vendor.eureka.hardware.fmradio.GetType import vendor.eureka.hardware.fmradio.GetType
import vendor.eureka.hardware.fmradio.IFMDevControl import vendor.eureka.hardware.fmradio.IFMDevControl
import vendor.eureka.hardware.fmradio.SetType
class NativeFMInterface { class NativeFMInterface {
private val mDevCtl: IFMDevControl val mDevCtl: IFMDevControl
private val mSysfsCtl: IFMDevControl val mSysfsCtl: IFMDevControl
private val mDefaultCtl: IFMDevControl val mDefaultCtl: IFMDevControl
init { init {
mDevCtl = IFMDevControl.Stub.asInterface(ServiceManager.waitForDeclaredService("vendor.eureka.hardware.fmradio.IFMDevControl/default")) mDevCtl = IFMDevControl.Stub.asInterface(ServiceManager.waitForDeclaredService("vendor.eureka.hardware.fmradio.IFMDevControl/default"))
mSysfsCtl = IFMDevControl.Stub.asInterface(ServiceManager.waitForDeclaredService("vendor.eureka.hardware.fmradio.IFMDevControl/support")) 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 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 android.widget.BaseAdapter
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import com.eurekateam.fmradio.* import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.NativeFMInterface 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.utils.Log
import com.eurekateam.fmradio.R
import com.google.android.material.textview.MaterialTextView 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() { class ListViewAdapter(private val mContext: Context) : BaseAdapter() {
private val mFMInterface = NativeFMInterface() private val mFMInterface = NativeFMInterface()
private val mListChannel = mFMInterface.mDefaultCtl.getFreqsList()
private var mListofViews = HashMap<Int, View>(30) private var mListofViews = HashMap<Int, View>(30)
override fun getCount(): Int { override fun getCount(): Int {
return MainFragment.mTracks.size return 30
} }
override fun getItem(p0: Int): Any { override fun getItem(p: Int): Any {
return MainFragment.mTracks[p0] return mListChannel[p]
} }
override fun getItemId(p0: Int): Long { override fun getItemId(p: Int): Long {
return p0.toLong() return p.toLong()
} }
override fun getView(id: Int, mConvertView: View?, parent: ViewGroup?): View { 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 = mAnotherConvertView.findViewById<MaterialTextView>(R.id.channel_list_title).text =
String.format( String.format(
mContext.getString(R.string.fm_radio_freq), 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 { mAnotherConvertView.findViewById<MaterialTextView>(R.id.channel_list_title).setOnClickListener {
mFMInterface.setFMFreq(MainFragment.fd, MainFragment.mTracks[id].toInt()) mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_FREQ, mListChannel[id])
MainFragment.mFreqCurrent = MainFragment.mTracks[id].toInt()
FileUtilities.writeToFile(
FileUtilities.mFMFreqFileName,
MainFragment.mFreqCurrent.toString(),
mContext
)
setCurrentFMChannel(id) setCurrentFMChannel(id)
} }
mAnotherConvertView.findViewById<AppCompatImageView>(R.id.star_button_list).let { 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, R.drawable.ic_star_filled,
mContext.theme mContext.theme
) )
val mIndex = MainFragment.mTracks[id].toInt() val mIndex = mListChannel[id]
if (MainFragment.mFavStats[mIndex] == null) { val mSharedPref = PreferenceManager.getDefaultSharedPreferences(mContext)
MainFragment.mFavStats.putIfAbsent(mIndex, false) val mBefore = mSharedPref.getBoolean("fav_$mIndex", false)
} if (mBefore) {
if (MainFragment.mFavStats[mIndex]!!) {
it.setImageDrawable(mStarFilled)
} else {
it.setImageDrawable(mStar) 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) setCurrentFMChannel(id)
} }
mListofViews[id] = mAnotherConvertView!! mListofViews[id] = mAnotherConvertView!!
@ -89,7 +85,7 @@ class ListViewAdapter(private val mContext: Context) : BaseAdapter() {
mListofViews[mPosition]?.setBackgroundColor( mListofViews[mPosition]?.setBackgroundColor(
ResourcesCompat.getColor( ResourcesCompat.getColor(
mContext.resources, mContext.resources,
android.R.color.system_accent3_400, android.R.color.system_accent2_400,
mContext.theme mContext.theme
) )
) )

View file

@ -6,38 +6,34 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.BaseAdapter import android.widget.BaseAdapter
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.NativeFMInterface import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.PebbleTextView import com.eurekateam.fmradio.PebbleTextView
import com.eurekateam.fmradio.R import com.eurekateam.fmradio.R
import com.eurekateam.fmradio.fragments.MainFragment import vendor.eureka.hardware.fmradio.SetType
import com.eurekateam.fmradio.utils.FileUtilities
class PebbleLayoutAdapter(private val mContext: Context) : BaseAdapter() { 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 { init {
for (mItem in MainFragment.mFavStats) { for (k in mListChannel) {
if (mItem.value) { if (mSharedPref.getBoolean("fav_$k", false)) mFavoriteList += k
mFavoriteList.add(mItem.key)
}
} }
mFavoriteList.sort()
var mData = ""
for (i in mFavoriteList) {
mData += "$i\n"
}
FileUtilities.writeToFile(FileUtilities.mFavouriteChannelFileName, mData, mContext)
} }
override fun getCount(): Int { override fun getCount(): Int {
return mFavoriteList.size return mFavoriteList.size
} }
override fun getItem(p0: Int): Any { override fun getItem(p: Int): Any {
return mFavoriteList[p0] return mFavoriteList[p]
} }
private val mFMInterface = NativeFMInterface() override fun getItemId(p: Int): Long {
override fun getItemId(p0: Int): Long { return p.toLong()
return p0.toLong()
} }
override fun getView(id: Int, mConvertView: View?, parent: ViewGroup?): View { override fun getView(id: Int, mConvertView: View?, parent: ViewGroup?): View {
@ -55,13 +51,7 @@ class PebbleLayoutAdapter(private val mContext: Context) : BaseAdapter() {
mContext.theme mContext.theme
) )
setOnClickListener { setOnClickListener {
mFMInterface.setFMFreq(MainFragment.fd, mFavoriteList[id]) mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_FREQ, mFavoriteList[id])
MainFragment.mFreqCurrent = mFavoriteList[id]
FileUtilities.writeToFile(
FileUtilities.mFMFreqFileName,
MainFragment.mFreqCurrent.toString(),
mContext
)
} }
} }
return mAnotherConvertView 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.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.ListView import android.widget.ListView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.eurekateam.fmradio.MainActivity import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.R import com.eurekateam.fmradio.R
import com.eurekateam.fmradio.MainActivity
import com.eurekateam.fmradio.adapters.ListViewAdapter 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 com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.Dispatchers import vendor.eureka.hardware.fmradio.SetType
import kotlinx.coroutines.GlobalScope import vendor.eureka.hardware.fmradio.GetType
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ChannelListFragment : class ChannelListFragment :
Fragment(R.layout.activity_channel_list), Fragment(R.layout.activity_channel_list),
View.OnClickListener { View.OnClickListener {
private lateinit var mListView: ListView private lateinit var mListView: ListView
private lateinit var mFloatingActionButton: FloatingActionButton private lateinit var mFloatingActionButton: FloatingActionButton
private val mNativeIF = NativeFMInterface()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -51,17 +55,21 @@ class ChannelListFragment :
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
GlobalScope.launch { mNativeIF.mDefaultCtl.setValue(SetType.SET_TYPE_FM_SEARCH_START, 0)
withContext(Dispatchers.IO) { requireActivity().window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
MainFragment.mRefreshTracks() WaitUntil.setTimer(
} requireActivity(),
withContext(Dispatchers.Main) { object : IWaitUntil {
(requireActivity() as MainActivity).getMySupportFragmentManager().apply { override fun cond(): Boolean = mNativeIF.mDefaultCtl.getValue(GetType.GET_TYPE_FM_MUTEX_LOCKED) == 0
beginTransaction().remove(this@ChannelListFragment).commit() override fun todo() {
executePendingTransactions() (requireActivity() as MainActivity).getMySupportFragmentManager().apply {
beginTransaction().add(R.id.container_view, this@ChannelListFragment).commit() 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 package com.eurekateam.fmradio.fragments
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
@ -9,25 +10,25 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.AppCompatSeekBar import androidx.appcompat.widget.AppCompatSeekBar
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import com.eurekateam.fmradio.NativeFMInterface import com.eurekateam.fmradio.NativeFMInterface
import com.eurekateam.fmradio.R import com.eurekateam.fmradio.R
import com.eurekateam.fmradio.enums.HeadsetState import com.eurekateam.fmradio.enums.HeadsetState
import com.eurekateam.fmradio.enums.OutputState
import com.eurekateam.fmradio.enums.PowerState 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.Log
import com.eurekateam.fmradio.utils.WaitUntil
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textview.MaterialTextView import com.google.android.material.textview.MaterialTextView
import kotlinx.coroutines.Dispatchers import vendor.eureka.hardware.fmradio.SetType
import kotlinx.coroutines.GlobalScope import vendor.eureka.hardware.fmradio.GetType
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.DecimalFormat import java.text.DecimalFormat
class MainFragment : class MainFragment :
@ -48,6 +49,9 @@ class MainFragment :
private lateinit var mAudioManager: AudioManager private lateinit var mAudioManager: AudioManager
private lateinit var mStar: Drawable private lateinit var mStar: Drawable
private lateinit var mStarFilled: Drawable private lateinit var mStarFilled: Drawable
private lateinit var mFavList: List<Int>
private lateinit var mSharedPref: SharedPreferences
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -83,6 +87,7 @@ class MainFragment :
mNextChannelBtn.setOnClickListener(this) mNextChannelBtn.setOnClickListener(this)
mOutputSwitch.setOnClickListener(this) mOutputSwitch.setOnClickListener(this)
mFavButton.setOnClickListener(this) mFavButton.setOnClickListener(this)
mSharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext())
var mIsLight = true var mIsLight = true
val nightModeFlags = requireContext().resources.configuration.uiMode and val nightModeFlags = requireContext().resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK Configuration.UI_MODE_NIGHT_MASK
@ -108,96 +113,33 @@ class MainFragment :
setBackgroundColor(resources.getColor(android.R.color.system_accent1_700, requireContext().theme)) setBackgroundColor(resources.getColor(android.R.color.system_accent1_700, requireContext().theme))
} }
} }
GlobalScope.launch { val mVolume = mSharedPref.getInt("volume", 8)
withContext(Dispatchers.IO) { mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, mVolume)
if (FileUtilities.checkIfExistFile(FileUtilities.mFavouriteChannelFileName, requireContext())) { mSeekBar.min = 1
val mFavData = FileUtilities.readFromFile( mSeekBar.max = 15
FileUtilities.mFavouriteChannelFileName, mSeekBar.progress = mVolume
requireContext() val mRestoreFreq = mSharedPref.getInt("freq", mFMInterface.mDevCtl.getValue(GetType.GET_TYPE_FM_LOWER_LIMIT))
) mFMInterface.mDefaultCtl.setValue(SetType.SET_TYPE_FM_FREQ, mRestoreFreq)
for (mItem in mFavData.split("\\r?\\n".toRegex())) { mFMFreq.text = mCleanFormat.format(mRestoreFreq.toFloat() / 1000)
if (mItem.isNotBlank()) { mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_THREAD, 1)
mFavStats[mItem.toInt()] = true 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(
var mMute = false requireActivity(),
if (mFreqCurrent == -1) { object : IWaitUntil {
mAudioManager.setParameters(PowerState.FM_POWER_OFF.mAudioParam) override fun cond(): Boolean = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_MUTEX_LOCKED) == 0
withContext(Dispatchers.Main) { override fun todo() {
mUpdateEnableDisable(false, mRootView) val mList = mFMInterface.mDefaultCtl.getFreqsList()
} for (i in mList) {
mMute = true if (mSharedPref.getBoolean("fav_$i", false)) mFavList += i
}
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) {
mSeekBar.min = 1
mSeekBar.max = 15
}
withContext(Dispatchers.IO) {
if (mVolume == -1) {
mVolume = 8
mFMInterface.setFMVolume(fd, mVolume)
withContext(Dispatchers.Main) {
mSeekBar.progress = mVolume
}
}
}
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)
}
} }
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
Toast.makeText(requireContext(), "Done", Toast.LENGTH_SHORT).show()
} }
} }
} )
// Update track list and fav button
return mRootView return mRootView
} }
@ -257,85 +199,55 @@ class MainFragment :
override fun onClick(v: View) { override fun onClick(v: View) {
when (v.id) { when (v.id) {
mOutputSwitch.id -> { mOutputSwitch.id -> {
if (mHeadset == OutputState.OUTPUT_HEADSET) { val mCurrent = mSharedPref.getBoolean("speaker", false)
if (!mCurrent) {
mOutputSwitch.setImageIcon( mOutputSwitch.setImageIcon(
Icon.createWithResource( Icon.createWithResource(
requireContext(), requireContext(),
R.drawable.ic_volume_up R.drawable.ic_volume_up
) )
) )
val ret = mFMInterface.setAudioRoute(true) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_SPEAKER_ROUTE, 1)
Log.i("mFMInterface.setAudioRoute return $ret") } else {
} else if (mHeadset == OutputState.OUTPUT_SPEAKER) {
mOutputSwitch.setImageIcon( mOutputSwitch.setImageIcon(
Icon.createWithResource( Icon.createWithResource(
requireContext(), requireContext(),
R.drawable.ic_headphones R.drawable.ic_headphones
) )
) )
val ret = mFMInterface.setAudioRoute(false) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_SPEAKER_ROUTE, 0)
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
} }
mSharedPref.edit().putBoolean("speaker", !mCurrent).apply()
} }
mVolumeUp.id -> { mVolumeUp.id -> {
if (mVolume < 15) { var mCurrentVolume = mSharedPref.getInt("volume", 8)
mVolume += 1 if (mCurrentVolume < 15) {
mCurrentVolume = mCurrentVolume + 1
} }
mFMInterface.setFMVolume(fd, mVolume) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, mCurrentVolume)
mSeekBar.progress = mVolume mSeekBar.progress = mCurrentVolume
Toast.makeText(requireContext(), "Volume set to $mVolume", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Volume set to $mCurrentVolume", Toast.LENGTH_SHORT).show()
FileUtilities.writeToFile( mSharedPref.edit().putInt("volume", mCurrentVolume).apply()
FileUtilities.mFMVolumeFileName,
mVolume.toString(),
requireContext()
)
} }
mVolumeDown.id -> { mVolumeDown.id -> {
if (mVolume > 0) { var mCurrentVolume = mSharedPref.getInt("volume", 8)
mVolume -= 1 if (mCurrentVolume > 0) {
mCurrentVolume = mCurrentVolume - 1
} }
mFMInterface.setFMVolume(fd, mVolume) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, mCurrentVolume)
mSeekBar.progress = mVolume mSeekBar.progress = mCurrentVolume
Toast.makeText(requireContext(), "Volume set to $mVolume", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Volume set to $mCurrentVolume", Toast.LENGTH_SHORT).show()
FileUtilities.writeToFile( mSharedPref.edit().putInt("volume", mCurrentVolume).apply()
FileUtilities.mFMVolumeFileName,
mVolume.toString(),
requireContext()
)
} }
mBeforeChannelBtn.id -> { mBeforeChannelBtn.id -> {
mFMInterface.setFMMute(fd, true) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 1)
val mTempFreq = mFMInterface.getBeforeChannel(fd) val mNewFreq = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_BEFORE_CHANNEL)
if (mTempFreq > mFMInterface.getFMLower(fd) && mTempFreq < mFMInterface.getFmUpper( mFMFreq.text = mCleanFormat.format(mNewFreq.toFloat() / 1000)
fd mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 0)
) if (mSharedPref.getBoolean("fav_$mNewFreq", false)) {
) { mFavButton.setImageDrawable(mStarFilled)
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)
}
} }
mSharedPref.edit().putInt("freq", mNewFreq).apply()
} }
mPowerBtn.id -> { mPowerBtn.id -> {
if (mFMPower) { if (mFMPower) {
@ -343,89 +255,40 @@ class MainFragment :
mFMFreq.text = getText(R.string.inital_freq) mFMFreq.text = getText(R.string.inital_freq)
} else { } else {
mAudioManager.setParameters(PowerState.FM_POWER_ON.mAudioParam) 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) mUpdateEnableDisable(!mFMPower)
mFMPower = !mFMPower mFMPower = !mFMPower
} }
mNextChannelBtn.id -> { mNextChannelBtn.id -> {
mFMInterface.setFMMute(fd, true) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 1)
val mTempFreq = mFMInterface.getNextChannel(fd) val mNewFreq = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_NEXT_CHANNEL)
if (mTempFreq > mFMInterface.getFMLower(fd) && mTempFreq < mFMInterface.getFmUpper( mFMFreq.text = mCleanFormat.format(mNewFreq.toFloat() / 1000)
fd mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_MUTE, 0)
) if (mSharedPref.getBoolean("fav_$mNewFreq", false)) {
) { mFavButton.setImageDrawable(mStarFilled)
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)
}
} }
mSharedPref.edit().putInt("freq", mNewFreq).apply()
} }
mFavButton.id -> { mFavButton.id -> {
val mIndex = mFreqCurrent val mCurrFreq = mFMInterface.mDefaultCtl.getValue(GetType.GET_TYPE_FM_FREQ)
if (mFavStats[mIndex] == null) { val mCurr = mSharedPref.getBoolean("fav_$mCurrFreq", false)
mFavStats.putIfAbsent(mIndex, false) if (mCurr) { mFavButton.setImageDrawable(mStar) } else { mFavButton.setImageDrawable(mStarFilled) }
} mSharedPref.edit().putBoolean("fav_$mCurrFreq", !mCurr).apply()
mFavStats[mIndex] = !mFavStats[mIndex]!!
mFavButton.let {
if (mFavStats[mIndex]!!) {
it.setImageDrawable(mStarFilled)
} else {
it.setImageDrawable(mStar)
}
}
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) { override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
mFMInterface.setFMVolume(fd, p1) mFMInterface.mDevCtl.setValue(SetType.SET_TYPE_FM_VOLUME, p1)
FileUtilities.writeToFile(FileUtilities.mFMVolumeFileName, p1.toString(), requireContext()) mSharedPref.edit().putInt("volume", p1).apply()
mVolume = p1
} }
override fun onStartTrackingTouch(p0: SeekBar?) {} override fun onStartTrackingTouch(p0: SeekBar?) {}
override fun onStopTrackingTouch(p0: SeekBar?) { override fun onStopTrackingTouch(p0: SeekBar?) {}
Toast.makeText(requireContext(), "Volume set to $mVolume", Toast.LENGTH_SHORT).show()
}
companion object { companion object {
private var mVolume = -1 var mFMPower = false
var fd = -1
var mHeadset = OutputState.OUTPUT_SPEAKER
var mFreqCurrent = -1
private var mFMPower = false
var mHeadSetPlugged: HeadsetState = HeadsetState.HEADSET_STATE_DISCONNECTED 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
)
}
}